24
24
-include("public_key.hrl").
26
-export([decode_cert/2, encode_cert/1, encode_tbs_cert/1]).
28
-export([old_decode_cert/2, old_encode_cert/1]). %% Debugging and testing new code.
26
-export([decode_cert/1, transform/2, supportedPublicKeyAlgorithms/1]).
30
28
%%====================================================================
31
29
%% Internal application API
32
30
%%====================================================================
34
decode_cert(DerCert, plain) ->
35
'OTP-PUB-KEY':decode('Certificate', DerCert);
36
decode_cert(DerCert, otp) ->
32
%%--------------------------------------------------------------------
33
-spec decode_cert(der_encoded()) -> {ok, #'OTPCertificate'{}}.
35
%% Description: Recursively decodes a Certificate.
36
%%--------------------------------------------------------------------
37
decode_cert(DerCert) ->
37
38
{ok, Cert} = 'OTP-PUB-KEY':decode('OTPCertificate', DerCert),
38
{ok, decode_all_otp(Cert)}.
40
old_decode_cert(DerCert, otp) ->
41
{ok, Cert} = 'OTP-PUB-KEY':decode('Certificate', DerCert),
42
{ok, plain_to_otp(Cert)}.
44
old_encode_cert(Cert) ->
45
PlainCert = otp_to_plain(Cert),
46
{ok, EncCert} = 'OTP-PUB-KEY':encode('Certificate', PlainCert),
47
list_to_binary(EncCert).
50
encode_cert(Cert = #'Certificate'{}) ->
51
{ok, EncCert} = 'OTP-PUB-KEY':encode('Certificate', Cert),
52
list_to_binary(EncCert);
53
encode_cert(C = #'OTPCertificate'{tbsCertificate = TBS =
57
subjectPublicKeyInfo=Spki0,
60
Issuer = transform(Issuer0,encode),
61
Subject = transform(Subject0,encode),
62
Spki = encode_supportedPublicKey(Spki0),
63
Exts = encode_extensions(Exts0),
64
%% io:format("Extensions ~p~n",[Exts]),
65
Cert = C#'OTPCertificate'{tbsCertificate=
66
TBS#'OTPTBSCertificate'{
67
issuer=Issuer, subject=Subject,
68
subjectPublicKeyInfo=Spki,
70
{ok, EncCert} = 'OTP-PUB-KEY':encode('OTPCertificate', Cert),
71
list_to_binary(EncCert).
73
encode_tbs_cert(TBS = #'OTPTBSCertificate'{
76
subjectPublicKeyInfo=Spki0,
78
Issuer = transform(Issuer0,encode),
79
Subject = transform(Subject0,encode),
80
Spki = encode_supportedPublicKey(Spki0),
81
Exts = encode_extensions(Exts0),
82
TBSCert = TBS#'OTPTBSCertificate'{issuer=Issuer,subject=Subject,
83
subjectPublicKeyInfo=Spki,extensions=Exts},
84
{ok, EncTBSCert} = 'OTP-PUB-KEY':encode('OTPTBSCertificate', TBSCert),
85
list_to_binary(EncTBSCert).
87
%%--------------------------------------------------------------------
88
%%% Internal functions
89
%%--------------------------------------------------------------------
91
decode_all_otp(C = #'OTPCertificate'{tbsCertificate = TBS =
95
subjectPublicKeyInfo=Spki0,
98
Issuer = transform(Issuer0,decode),
99
Subject = transform(Subject0,decode),
100
Spki = decode_supportedPublicKey(Spki0),
101
Exts = decode_extensions(Exts0),
102
%% io:format("Extensions ~p~n",[Exts]),
103
C#'OTPCertificate'{tbsCertificate=
104
TBS#'OTPTBSCertificate'{
105
issuer=Issuer, subject=Subject,
106
subjectPublicKeyInfo=Spki,extensions=Exts}}.
39
#'OTPCertificate'{tbsCertificate = TBS} = Cert,
40
{ok, Cert#'OTPCertificate'{tbsCertificate = decode_tbs(TBS)}}.
42
%%--------------------------------------------------------------------
43
-spec transform(term(), encode | decode) ->term().
45
%% Description: Transforms between encoded and decode otp formated
47
%%--------------------------------------------------------------------
49
transform(#'OTPCertificate'{tbsCertificate = TBS} = Cert, encode) ->
50
Cert#'OTPCertificate'{tbsCertificate=encode_tbs(TBS)};
51
transform(#'OTPCertificate'{tbsCertificate = TBS} = Cert, decode) ->
52
Cert#'OTPCertificate'{tbsCertificate=decode_tbs(TBS)};
53
transform(#'OTPTBSCertificate'{}= TBS, encode) ->
55
transform(#'OTPTBSCertificate'{}= TBS, decode) ->
57
transform(#'AttributeTypeAndValue'{type=Id,value=Value0} = ATAV, Func) ->
59
case attribute_type(Id) of
60
Type when is_atom(Type) -> 'OTP-PUB-KEY':Func(Type, Value0);
61
_UnknownType -> {ok, Value0}
63
ATAV#'AttributeTypeAndValue'{value=Value};
64
transform(AKI = #'AuthorityKeyIdentifier'{authorityCertIssuer=ACI},Func) ->
65
AKI#'AuthorityKeyIdentifier'{authorityCertIssuer=transform(ACI,Func)};
66
transform(List = [{directoryName, _}],Func) ->
67
[{directoryName, transform(Value,Func)} || {directoryName, Value} <- List];
68
transform({directoryName, Value},Func) ->
69
{directoryName, transform(Value,Func)};
70
transform({rdnSequence, SeqList},Func) when is_list(SeqList) ->
73
lists:map(fun(Element) -> transform(Element,Func) end, Seq)
75
transform(#'NameConstraints'{permittedSubtrees=Permitted, excludedSubtrees=Excluded}, Func) ->
76
#'NameConstraints'{permittedSubtrees=transform_sub_tree(Permitted,Func),
77
excludedSubtrees=transform_sub_tree(Excluded,Func)};
82
%%--------------------------------------------------------------------
83
-spec supportedPublicKeyAlgorithms(Oid::tuple()) -> asn1_type().
85
%% Description: Returns the public key type for an algorithm
86
%% identifier tuple as found in SubjectPublicKeyInfo.
88
%%--------------------------------------------------------------------
110
89
supportedPublicKeyAlgorithms(?'rsaEncryption') -> 'RSAPublicKey';
111
90
supportedPublicKeyAlgorithms(?'id-dsa') -> 'DSAPublicKey';
112
91
supportedPublicKeyAlgorithms(?'dhpublicnumber') -> 'DHPublicKey';
113
92
supportedPublicKeyAlgorithms(?'id-keyExchangeAlgorithm') -> 'KEA-PublicKey';
114
93
supportedPublicKeyAlgorithms(?'id-ecPublicKey') -> 'ECPoint'.
95
%%--------------------------------------------------------------------
96
%%% Internal functions
97
%%--------------------------------------------------------------------
116
101
decode_supportedPublicKey(#'OTPSubjectPublicKeyInfo'{algorithm= PA =
117
102
#'PublicKeyAlgorithm'{algorithm=Algo},
118
103
subjectPublicKey = {0,SPK0}}) ->
189
transform(#'AttributeTypeAndValue'{type=Id,value=Value0} = ATAV, Func) ->
191
case attribute_type(Id) of
192
Type when is_atom(Type) -> 'OTP-PUB-KEY':Func(Type, Value0);
193
_UnknownType -> {ok, Value0}
195
ATAV#'AttributeTypeAndValue'{value=Value};
196
transform(AKI = #'AuthorityKeyIdentifier'{authorityCertIssuer=ACI},Func) ->
197
AKI#'AuthorityKeyIdentifier'{authorityCertIssuer=transform(ACI,Func)};
198
transform(List = [{directoryName, _}],Func) ->
199
[{directoryName, transform(Value,Func)} || {directoryName, Value} <- List];
200
transform({directoryName, Value},Func) ->
201
{directoryName, transform(Value,Func)};
202
transform({rdnSequence, SeqList},Func) when is_list(SeqList) ->
204
lists:map(fun(Seq) ->
205
lists:map(fun(Element) -> transform(Element,Func) end, Seq)
207
%% transform(List = [{rdnSequence, _}|_],Func) ->
208
%% lists:map(fun(Element) -> transform(Element,Func) end, List);
209
transform(#'NameConstraints'{permittedSubtrees=Permitted, excludedSubtrees=Excluded}, Func) ->
210
Res = #'NameConstraints'{permittedSubtrees=transform_sub_tree(Permitted,Func),
211
excludedSubtrees=transform_sub_tree(Excluded,Func)},
212
%% io:format("~p~n",[Res]),
214
transform(Other,_) ->
174
encode_tbs(TBS=#'OTPTBSCertificate'{issuer=Issuer0,
176
subjectPublicKeyInfo=Spki0,
177
extensions=Exts0}) ->
178
Issuer = transform(Issuer0,encode),
179
Subject = transform(Subject0,encode),
180
Spki = encode_supportedPublicKey(Spki0),
181
Exts = encode_extensions(Exts0),
182
TBS#'OTPTBSCertificate'{issuer=Issuer, subject=Subject,
183
subjectPublicKeyInfo=Spki,extensions=Exts}.
185
decode_tbs(TBS = #'OTPTBSCertificate'{issuer=Issuer0,
187
subjectPublicKeyInfo=Spki0,
188
extensions=Exts0}) ->
189
Issuer = transform(Issuer0,decode),
190
Subject = transform(Subject0,decode),
191
Spki = decode_supportedPublicKey(Spki0),
192
Exts = decode_extensions(Exts0),
193
TBS#'OTPTBSCertificate'{issuer=Issuer, subject=Subject,
194
subjectPublicKeyInfo=Spki,extensions=Exts}.
216
196
transform_sub_tree(asn1_NOVALUE,_) -> asn1_NOVALUE;
217
197
transform_sub_tree(TreeList,Func) ->
218
198
[Tree#'GeneralSubtree'{base=transform(Name,Func)} ||
236
216
attribute_type(?'id-domainComponent') -> 'DomainComponent';
237
217
attribute_type(?'id-emailAddress') -> 'EmailAddress';
238
218
attribute_type(Type) -> Type.
240
%%% Old code transforms
242
plain_to_otp(#'Certificate'{tbsCertificate = TBSCert,
243
signatureAlgorithm = SigAlg,
244
signature = Signature} = Cert) ->
245
Cert#'Certificate'{tbsCertificate = plain_to_otp(TBSCert),
246
signatureAlgorithm = plain_to_otp(SigAlg),
247
signature = plain_to_otp(Signature)};
249
plain_to_otp(#'TBSCertificate'{signature = Signature,
252
subjectPublicKeyInfo = SPubKeyInfo,
253
extensions = Extensions} = TBSCert) ->
255
TBSCert#'TBSCertificate'{signature = plain_to_otp(Signature),
256
issuer = plain_to_otp(Issuer),
258
plain_to_otp(Subject),
259
subjectPublicKeyInfo =
260
plain_to_otp(SPubKeyInfo),
262
plain_to_otp_extensions(Extensions)
265
plain_to_otp(#'AlgorithmIdentifier'{algorithm = Algorithm,
266
parameters = Params}) ->
268
#'SignatureAlgorithm-Any'{algorithm = Algorithm,
269
parameters = Params},
270
{ok, AnyEnc} = 'OTP-PUB-KEY':encode('SignatureAlgorithm-Any',
272
{ok, SignAlg} = 'OTP-PUB-KEY':decode('SignatureAlgorithm',
273
list_to_binary(AnyEnc)),
276
plain_to_otp({rdnSequence, SeqList}) when is_list(SeqList) ->
278
lists:map(fun(Seq) ->
279
lists:map(fun(Element) ->
280
plain_to_otp(Element)
285
plain_to_otp(#'AttributeTypeAndValue'{} = ATAV) ->
287
'OTP-PUB-KEY':encode('AttributeTypeAndValue', ATAV),
288
{ok, ATAVDec} = 'OTP-PUB-KEY':decode('OTPAttributeTypeAndValue',
289
list_to_binary(ATAVEnc)),
290
#'AttributeTypeAndValue'{type = ATAVDec#'OTPAttributeTypeAndValue'.type,
292
ATAVDec#'OTPAttributeTypeAndValue'.value};
294
plain_to_otp(#'SubjectPublicKeyInfo'{algorithm =
295
#'AlgorithmIdentifier'{algorithm
299
subjectPublicKey = PublicKey}) ->
301
AnyAlgo = #'PublicKeyAlgorithm'{algorithm = Algo,
302
parameters = Params},
303
{0, AnyKey} = PublicKey,
304
AnyDec = #'OTPSubjectPublicKeyInfo-Any'{algorithm = AnyAlgo,
305
subjectPublicKey = AnyKey},
307
'OTP-PUB-KEY':encode('OTPSubjectPublicKeyInfo-Any', AnyDec),
308
{ok, InfoDec} = 'OTP-PUB-KEY':decode('OTPOLDSubjectPublicKeyInfo',
309
list_to_binary(AnyEnc)),
311
AlgorithmDec = InfoDec#'OTPOLDSubjectPublicKeyInfo'.algorithm,
312
AlgoDec = AlgorithmDec#'OTPOLDSubjectPublicKeyInfo_algorithm'.algo,
313
NewParams = AlgorithmDec#'OTPOLDSubjectPublicKeyInfo_algorithm'.parameters,
314
PublicKeyDec = InfoDec#'OTPOLDSubjectPublicKeyInfo'.subjectPublicKey,
316
#'SubjectPublicKeyInfoAlgorithm'{algorithm = AlgoDec,
317
parameters = NewParams},
318
#'SubjectPublicKeyInfo'{algorithm = NewAlgorithmDec,
319
subjectPublicKey = PublicKeyDec
322
plain_to_otp(#'Extension'{extnID = ExtID,
325
when ExtID == ?'id-ce-authorityKeyIdentifier';
326
ExtID == ?'id-ce-subjectKeyIdentifier';
327
ExtID == ?'id-ce-keyUsage';
328
ExtID == ?'id-ce-privateKeyUsagePeriod';
329
ExtID == ?'id-ce-certificatePolicies';
330
ExtID == ?'id-ce-policyMappings';
331
ExtID == ?'id-ce-subjectAltName';
332
ExtID == ?'id-ce-issuerAltName';
333
ExtID == ?'id-ce-subjectDirectoryAttributes';
334
ExtID == ?'id-ce-basicConstraints';
335
ExtID == ?'id-ce-nameConstraints';
336
ExtID == ?'id-ce-policyConstraints';
337
ExtID == ?'id-ce-extKeyUsage';
338
ExtID == ?'id-ce-cRLDistributionPoints';
339
ExtID == ?'id-ce-inhibitAnyPolicy';
340
ExtID == ?'id-ce-freshestCRL' ->
341
ExtAny = #'Extension-Any'{extnID = ExtID,
344
{ok, AnyEnc} = 'OTP-PUB-KEY':encode('Extension-Any', ExtAny),
345
{ok, ExtDec} = 'OTP-PUB-KEY':decode('OTPExtension',
346
list_to_binary(AnyEnc)),
348
ExtValue = plain_to_otp_extension_value(ExtID,
349
ExtDec#'OTPExtension'.extnValue),
350
#'Extension'{extnID = ExtID,
351
critical = ExtDec#'OTPExtension'.critical,
352
extnValue = ExtValue};
354
plain_to_otp(#'Extension'{} = Ext) ->
357
plain_to_otp(#'AuthorityKeyIdentifier'{} = Ext) ->
358
CertIssuer = Ext#'AuthorityKeyIdentifier'.authorityCertIssuer,
359
Ext#'AuthorityKeyIdentifier'{authorityCertIssuer =
360
plain_to_otp(CertIssuer)};
363
plain_to_otp([{directoryName, Value}]) ->
364
[{directoryName, plain_to_otp(Value)}];
366
plain_to_otp(Value) ->
369
otp_to_plain(#'Certificate'{tbsCertificate = TBSCert,
370
signatureAlgorithm = SigAlg,
371
signature = Signature} = Cert) ->
372
Cert#'Certificate'{tbsCertificate = otp_to_plain(TBSCert),
374
otp_to_plain(SigAlg),
375
signature = otp_to_plain(Signature)};
377
otp_to_plain(#'TBSCertificate'{signature = Signature,
380
subjectPublicKeyInfo = SPubKeyInfo,
381
extensions = Extensions} = TBSCert) ->
383
TBSCert#'TBSCertificate'{signature = otp_to_plain(Signature),
384
issuer = otp_to_plain(Issuer),
386
otp_to_plain(Subject),
387
subjectPublicKeyInfo =
388
otp_to_plain(SPubKeyInfo),
389
extensions = otp_to_plain_extensions(Extensions)
392
otp_to_plain(#'SignatureAlgorithm'{} = SignAlg) ->
393
{ok, EncSignAlg} = 'OTP-PUB-KEY':encode('SignatureAlgorithm', SignAlg),
394
{ok, #'SignatureAlgorithm-Any'{algorithm = Algorithm,
395
parameters = Params}} =
396
'OTP-PUB-KEY':decode('SignatureAlgorithm-Any',
397
list_to_binary(EncSignAlg)),
398
#'AlgorithmIdentifier'{algorithm = Algorithm,
399
parameters = Params};
401
otp_to_plain({rdnSequence, SeqList}) when is_list(SeqList) ->
403
lists:map(fun(Seq) ->
404
lists:map(fun(Element) ->
405
otp_to_plain(Element)
410
otp_to_plain(#'AttributeTypeAndValue'{type = Type, value = Value}) ->
412
'OTP-PUB-KEY':encode('OTPAttributeTypeAndValue',
413
#'OTPAttributeTypeAndValue'{type = Type,
415
{ok, ATAVDec} = 'OTP-PUB-KEY':decode('AttributeTypeAndValue',
416
list_to_binary(ATAVEnc)),
419
otp_to_plain(#'SubjectPublicKeyInfo'{algorithm =
420
#'SubjectPublicKeyInfoAlgorithm'{
424
subjectPublicKey = PublicKey}) ->
426
OtpAlgo = #'OTPOLDSubjectPublicKeyInfo_algorithm'{algo = Algo,
427
parameters = Params},
428
OtpDec = #'OTPOLDSubjectPublicKeyInfo'{algorithm = OtpAlgo,
429
subjectPublicKey = PublicKey},
431
'OTP-PUB-KEY':encode('OTPOLDSubjectPublicKeyInfo', OtpDec),
433
{ok, AnyDec} = 'OTP-PUB-KEY':decode('OTPSubjectPublicKeyInfo-Any',
434
list_to_binary(OtpEnc)),
436
#'OTPSubjectPublicKeyInfo-Any'{algorithm = #'PublicKeyAlgorithm'{
438
parameters = NewParams},
439
subjectPublicKey = Bin} = AnyDec,
441
#'SubjectPublicKeyInfo'{algorithm =
442
#'AlgorithmIdentifier'{
444
parameters = plain_key_params(NewParams)},
449
otp_to_plain(#'Extension'{extnID = ExtID,
450
extnValue = Value} = Ext) ->
452
otp_to_plain_extension_value(ExtID, Value),
454
Ext#'Extension'{extnValue = ExtValue};
456
otp_to_plain(#'AuthorityKeyIdentifier'{} = Ext) ->
457
CertIssuer = Ext#'AuthorityKeyIdentifier'.authorityCertIssuer,
458
Ext#'AuthorityKeyIdentifier'{authorityCertIssuer =
459
otp_to_plain(CertIssuer)};
461
otp_to_plain([{directoryName, Value}]) ->
462
[{directoryName, otp_to_plain(Value)}];
464
otp_to_plain(Value) ->
467
plain_key_params('NULL') ->
469
plain_key_params(Value) ->
472
plain_to_otp_extension_value(?'id-ce-authorityKeyIdentifier', Value) ->
474
plain_to_otp_extension_value(_, Value) ->
477
plain_to_otp_extensions(Exts) when is_list(Exts) ->
478
lists:map(fun(Ext) -> plain_to_otp(Ext) end, Exts).
480
otp_to_plain_extension_value(?'id-ce-authorityKeyIdentifier', Value) ->
481
{ok, Enc} = 'OTP-PUB-KEY':encode('AuthorityKeyIdentifier',
482
otp_to_plain(Value)),
483
otp_to_plain_extension_value_format(Enc);
484
otp_to_plain_extension_value(?'id-ce-subjectKeyIdentifier', Value) ->
485
{ok, Enc} = 'OTP-PUB-KEY':encode('SubjectKeyIdentifier', Value),
486
otp_to_plain_extension_value_format(Enc);
487
otp_to_plain_extension_value(?'id-ce-keyUsage', Value) ->
488
{ok, Enc} = 'OTP-PUB-KEY':encode('KeyUsage', Value),
489
otp_to_plain_extension_value_format(Enc);
490
otp_to_plain_extension_value(?'id-ce-privateKeyUsagePeriod', Value) ->
491
{ok, Enc} = 'OTP-PUB-KEY':encode('PrivateKeyUsagePeriod', Value),
492
otp_to_plain_extension_value_format(Enc);
493
otp_to_plain_extension_value(?'id-ce-certificatePolicies', Value) ->
494
{ok, Enc} = 'OTP-PUB-KEY':encode('CertificatePolicies', Value),
495
otp_to_plain_extension_value_format(Enc);
496
otp_to_plain_extension_value(?'id-ce-policyMappings', Value) ->
497
{ok, Enc} = 'OTP-PUB-KEY':encode('PolicyMappings', Value),
498
otp_to_plain_extension_value_format(Enc);
499
otp_to_plain_extension_value(?'id-ce-subjectAltName', Value) ->
500
{ok, Enc} = 'OTP-PUB-KEY':encode('SubjectAltName', Value),
501
otp_to_plain_extension_value_format(Enc);
502
otp_to_plain_extension_value(?'id-ce-issuerAltName', Value) ->
503
{ok, Enc} = 'OTP-PUB-KEY':encode('IssuerAltName', Value),
504
otp_to_plain_extension_value_format(Enc);
505
otp_to_plain_extension_value(?'id-ce-subjectDirectoryAttributes', Value) ->
506
{ok, Enc} = 'OTP-PUB-KEY':encode('SubjectDirectoryAttributes', Value),
507
otp_to_plain_extension_value_format(Enc);
508
otp_to_plain_extension_value(?'id-ce-basicConstraints', Value) ->
509
{ok, Enc} = 'OTP-PUB-KEY':encode('BasicConstraints', Value),
510
otp_to_plain_extension_value_format(Enc);
511
otp_to_plain_extension_value(?'id-ce-nameConstraints', Value) ->
512
{ok, Enc} = 'OTP-PUB-KEY':encode('NameConstraints', Value),
513
otp_to_plain_extension_value_format(Enc);
514
otp_to_plain_extension_value(?'id-ce-policyConstraints', Value) ->
515
{ok, Enc} = 'OTP-PUB-KEY':encode('PolicyConstraints', Value),
516
otp_to_plain_extension_value_format(Enc);
517
otp_to_plain_extension_value(?'id-ce-extKeyUsage', Value) ->
518
{ok, Enc} = 'OTP-PUB-KEY':encode('ExtKeyUsage', Value),
519
otp_to_plain_extension_value_format(Enc);
520
otp_to_plain_extension_value(?'id-ce-cRLDistributionPoints', Value) ->
521
{ok, Enc} = 'OTP-PUB-KEY':encode('CRLDistributionPoints', Value),
522
otp_to_plain_extension_value_format(Enc);
523
otp_to_plain_extension_value(?'id-ce-inhibitAnyPolicy', Value) ->
524
{ok, Enc} = 'OTP-PUB-KEY':encode('InhibitAnyPolicy', Value),
525
otp_to_plain_extension_value_format(Enc);
526
otp_to_plain_extension_value(?'id-ce-freshestCRL', Value) ->
527
{ok, Enc} = 'OTP-PUB-KEY':encode('FreshestCRL', Value),
528
otp_to_plain_extension_value_format(Enc);
529
otp_to_plain_extension_value(_Id, Value) ->
532
otp_to_plain_extension_value_format(Value) ->
533
list_to_binary(Value).
535
otp_to_plain_extensions(Exts) when is_list(Exts) ->
536
lists:map(fun(Ext) ->