1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2008-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22
23-module(public_key).
24
25-include("public_key.hrl").
26
27-export([pem_decode/1, pem_encode/1,
28	 der_decode/2, der_encode/2,
29	 pem_entry_decode/1,
30	 pem_entry_decode/2,
31	 pem_entry_encode/2,
32	 pem_entry_encode/3,
33	 pkix_decode_cert/2, pkix_encode/3,
34	 encrypt_private/2, encrypt_private/3,
35	 decrypt_private/2, decrypt_private/3,
36	 encrypt_public/2, encrypt_public/3,
37	 decrypt_public/2, decrypt_public/3,
38	 dh_gex_group/4,
39	 dh_gex_group_sizes/0,
40	 sign/3, sign/4, verify/4, verify/5,
41	 generate_key/1,
42	 compute_key/2, compute_key/3,
43	 pkix_sign/2, pkix_verify/2,
44	 pkix_hash_type/1,
45	 pkix_sign_types/1,
46	 pkix_is_self_signed/1,
47	 pkix_is_fixed_dh_cert/1,
48	 pkix_is_issuer/2,
49	 pkix_issuer_id/2,
50	 pkix_subject_id/1,
51         pkix_normalize_name/1,
52	 pkix_path_validation/3,
53	 pkix_verify_hostname/2, pkix_verify_hostname/3,
54         pkix_verify_hostname_match_fun/1,
55	 ssh_curvename2oid/1, oid2ssh_curvename/1,
56	 pkix_crls_validate/3,
57	 pkix_dist_point/1,
58	 pkix_dist_points/1,
59	 pkix_match_dist_point/2,
60	 pkix_crl_verify/2,
61	 pkix_crl_issuer/1,
62	 short_name_hash/1,
63         pkix_test_data/1,
64         pkix_test_root_cert/2,
65         pkix_ocsp_validate/5,
66         ocsp_responder_id/1,
67         ocsp_extensions/1
68	]).
69
70%%----------------
71%% To be moved to ssh and deprecated:
72-export([ssh_decode/2, ssh_encode/2,
73         ssh_hostkey_fingerprint/1, ssh_hostkey_fingerprint/2
74        ]).
75
76-deprecated([{ssh_decode,2, "use ssh_file:decode/2 instead"},
77             {ssh_encode,2, "use ssh_file:encode/2 instead"},
78             {ssh_hostkey_fingerprint,1, "use ssh:hostkey_fingerprint/1 instead"},
79             {ssh_hostkey_fingerprint,2, "use ssh:hostkey_fingerprint/2 instead"}
80            ]).
81
82-compile([{nowarn_deprecated_function,
83           [{public_key,ssh_decode,2},
84            {public_key,ssh_encode,2}
85           ]}
86         ]).
87
88%% When removing for OTP-25.0, remember to also remove
89%%   - most of pubkey_ssh.erl except
90%%       + dh_gex_group/4
91%%       + dh_gex_group_sizes/0
92%%   - pubkey_pem:pem_start({no_asn1, new_openssh})
93%%   - pubkey_pem:pem_end(<<"-----BEGIN OPENSSH PRIVATE KEY-----">>)
94%%   - pubkey_pem:asn1_type(<<"-----BEGIN OPENSSH PRIVATE KEY-----">>) -> {no_asn1, new_openssh}
95
96%%----------------------------------------------------------------
97%% Types
98-export_type([public_key/0,
99              private_key/0,
100              pem_entry/0,
101	      pki_asn1_type/0,
102              asn1_type/0,
103              ssh_file/0,
104              der_encoded/0,
105              key_params/0,
106              digest_type/0,
107              issuer_name/0,
108              cert/0,
109              combined_cert/0,
110              cert_id/0,
111              oid/0,
112              cert_opt/0,
113              chain_opts/0,
114              conf_opt/0,
115              test_config/0,
116              test_root_cert/0]).
117
118
119-type public_key()           ::  rsa_public_key() | rsa_pss_public_key() | dsa_public_key() | ec_public_key() | ed_public_key() .
120-type private_key()          ::  rsa_private_key() | rsa_pss_private_key() | dsa_private_key() | ec_private_key() | ed_private_key() .
121-type rsa_public_key()       ::  #'RSAPublicKey'{}.
122-type rsa_private_key()      ::  #'RSAPrivateKey'{}.
123-type dss_public_key()       :: integer().
124-type rsa_pss_public_key()   ::  {rsa_pss_public_key(), #'RSASSA-PSS-params'{}}.
125-type rsa_pss_private_key()  ::  { #'RSAPrivateKey'{}, #'RSASSA-PSS-params'{}}.
126-type dsa_private_key()      ::  #'DSAPrivateKey'{}.
127-type dsa_public_key()       :: {dss_public_key(), #'Dss-Parms'{}}.
128-type public_key_params()    :: 'NULL' | #'RSASSA-PSS-params'{} |  {namedCurve, oid()} | #'ECParameters'{} | #'Dss-Parms'{}.
129-type ecpk_parameters() :: {ecParameters, #'ECParameters'{}} | {namedCurve, Oid::tuple()}.
130-type ecpk_parameters_api() :: ecpk_parameters() | #'ECParameters'{} | {namedCurve, Name::crypto:ec_named_curve()}.
131-type ec_public_key()        :: {#'ECPoint'{}, ecpk_parameters_api()}.
132-type ec_private_key()       :: #'ECPrivateKey'{}.
133-type ed_public_key()        :: {#'ECPoint'{}, ed_params()}.
134-type ed_legacy_pubkey()     ::  {ed_pub, ed25519|ed448, Key::binary()}.
135-type ed_private_key()       :: #'ECPrivateKey'{parameters :: ed_params()}.
136-type ed_legacy_privkey()        :: {ed_pri, ed25519|ed448, Pub::binary(), Priv::binary()}.
137-type ed_oid_name()            ::  'id-Ed25519' | 'id-Ed448'.
138-type ed_params()            ::  {namedCurve, ed_oid_name()}.
139-type key_params()           :: #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{} |
140                                {rsa, Size::integer(), PubExp::integer()}.
141-type der_encoded()          :: binary().
142-type pki_asn1_type()        ::  'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey'
143			       | 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter'
144                               | 'SubjectPublicKeyInfo' | 'PrivateKeyInfo' |
145				 'CertificationRequest' | 'CertificateList' |
146				 'ECPrivateKey' | 'EcpkParameters'.
147-type pem_entry()            :: {pki_asn1_type(),
148				 der_or_encrypted_der(),
149				 not_encrypted | cipher_info()
150				}.
151-type der_or_encrypted_der() :: binary().
152-type cipher_info()          :: {cipher(),
153                                 cipher_info_params()} .
154-type cipher()               :: string() . % "RC2-CBC" | "DES-CBC" | "DES-EDE3-CBC",
155-type cipher_info_params()   :: salt()
156                              | {#'PBEParameter'{}, digest_type()}
157                              | #'PBES2-params'{} .
158
159-type salt()                 :: binary(). % crypto:strong_rand_bytes(8)
160-type asn1_type()            :: atom(). %% see "OTP-PUB-KEY.hrl
161-type ssh_file()             :: openssh_public_key | rfc4716_public_key | known_hosts |
162				auth_keys.
163-type digest_type()          :: none % None is for backwards compatibility
164                              | sha1 % Backwards compatibility
165                              | crypto:rsa_digest_type()
166                              | crypto:dss_digest_type()
167                              | crypto:ecdsa_digest_type().
168-type crl_reason()           ::  unspecified | keyCompromise | cACompromise | affiliationChanged | superseded
169			       | cessationOfOperation | certificateHold | privilegeWithdrawn |  aACompromise.
170-type oid()                  :: tuple().
171-type cert_id()              :: {SerialNr::integer(), issuer_name()} .
172-type issuer_name()          :: {rdnSequence,[[#'AttributeTypeAndValue'{}]]} .
173-type bad_cert_reason()      :: cert_expired | invalid_issuer | invalid_signature | name_not_permitted | missing_basic_constraint | invalid_key_usage | {revoked, crl_reason()} | atom().
174
175-type combined_cert()        :: #cert{}.
176-type cert()                 :: der_cert() | otp_cert().
177-type der_cert()             :: der_encoded().
178-type otp_cert()             :: #'OTPCertificate'{}.
179-type public_key_info()      :: {key_oid_name(),  rsa_public_key() | #'ECPoint'{} | dss_public_key(),  public_key_params()}.
180-type key_oid_name()              :: 'rsaEncryption' | 'id-RSASSA-PSS' | 'id-ecPublicKey' | 'id-Ed25519' | 'id-Ed448' | 'id-dsa'.
181-type cert_opt()  :: {digest, public_key:digest_type()} |
182                     {key, public_key:key_params() | public_key:private_key()} |
183                     {validity, {From::erlang:timestamp(), To::erlang:timestamp()}} |
184                     {extensions, [#'Extension'{}]}.
185-type chain_end()   :: root | peer.
186-type chain_opts()  :: #{chain_end() := [cert_opt()],  intermediates =>  [[cert_opt()]]}.
187-type conf_opt()    :: {cert, public_key:der_encoded()} |
188                       {key,  public_key:private_key()} |
189                       {cacerts, [public_key:der_encoded()]}.
190-type test_config() ::
191        #{server_config := [conf_opt()],  client_config :=  [conf_opt()]}.
192-type test_root_cert() ::
193        #{cert := der_encoded(), key := public_key:private_key()}.
194
195-define(UINT32(X), X:32/unsigned-big-integer).
196-define(DER_NULL, <<5, 0>>).
197
198%%====================================================================
199%% API
200%%====================================================================
201%%--------------------------------------------------------------------
202-spec pem_decode(binary()) -> [pem_entry()].
203%%
204%% Description: Decode PEM binary data and return
205%% entries as asn1 der encoded entities.
206%%--------------------------------------------------------------------
207pem_decode(PemBin) when is_binary(PemBin) ->
208    pubkey_pem:decode(PemBin).
209
210%%--------------------------------------------------------------------
211-spec pem_encode([pem_entry()]) -> binary().
212%%
213%% Description: Creates a PEM binary.
214%%--------------------------------------------------------------------
215pem_encode(PemEntries) when is_list(PemEntries) ->
216    iolist_to_binary(pubkey_pem:encode(PemEntries)).
217
218%%--------------------------------------------------------------------
219%% Description: Decodes a pem entry. pem_decode/1 returns a list of
220%% pem entries.
221%%--------------------------------------------------------------------
222-spec pem_entry_decode(PemEntry) -> term() when PemEntry :: pem_entry() .
223
224pem_entry_decode({'SubjectPublicKeyInfo', Der, _}) ->
225    {_, {'AlgorithmIdentifier', AlgId, Params}, Key0}
226        = der_decode('SubjectPublicKeyInfo', Der),
227    KeyType = pubkey_cert_records:supportedPublicKeyAlgorithms(AlgId),
228    case KeyType of
229        'RSAPublicKey' ->
230            der_decode(KeyType, Key0);
231        'DSAPublicKey' ->
232            {params, DssParams} = der_decode('DSAParams', Params),
233            {der_decode(KeyType, Key0), DssParams};
234        'ECPoint' ->
235	    ECCParams = der_decode('EcpkParameters', Params),
236            {#'ECPoint'{point = Key0}, ECCParams}
237    end;
238pem_entry_decode({{no_asn1,new_openssh}, Special, not_encrypted}) ->
239    ssh_decode(Special, new_openssh);
240pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type),
241						      is_binary(Der) ->
242    der_decode(Asn1Type, Der).
243
244-spec pem_entry_decode(PemEntry, Password) -> term() when PemEntry :: pem_entry(),
245                                                          Password :: string() .
246pem_entry_decode({Asn1Type, Der, not_encrypted}, _) when is_atom(Asn1Type),
247							 is_binary(Der) ->
248    der_decode(Asn1Type, Der);
249pem_entry_decode({Asn1Type, CryptDer, {Cipher, #'PBES2-params'{}}} = PemEntry,
250		 Password) when is_atom(Asn1Type) andalso
251				is_binary(CryptDer) andalso
252				is_list(Cipher) ->
253    do_pem_entry_decode(PemEntry, Password);
254pem_entry_decode({Asn1Type, CryptDer, {Cipher, {#'PBEParameter'{},_}}} = PemEntry,
255 		 Password) when is_atom(Asn1Type) andalso
256 				is_binary(CryptDer) andalso
257 				is_list(Cipher) andalso
258				is_list(Password) ->
259    do_pem_entry_decode(PemEntry, Password);
260pem_entry_decode({Asn1Type, CryptDer, {Cipher, Salt}} = PemEntry,
261		 Password) when is_atom(Asn1Type) andalso
262				is_binary(CryptDer) andalso
263				is_list(Cipher) andalso
264				is_binary(Salt) andalso
265				((erlang:byte_size(Salt) == 8) or (erlang:byte_size(Salt) == 16)) andalso
266				is_list(Password) ->
267    do_pem_entry_decode(PemEntry, Password).
268
269
270%%--------------------------------------------------------------------
271%%
272%% Description: Creates a pem entry that can be feed to pem_encode/1.
273%%--------------------------------------------------------------------
274-spec pem_entry_encode(Asn1Type, Entity) -> pem_entry() when Asn1Type :: pki_asn1_type(),
275                                                             Entity :: term() .
276
277pem_entry_encode('SubjectPublicKeyInfo', Entity=#'RSAPublicKey'{}) ->
278    KeyDer = der_encode('RSAPublicKey', Entity),
279    Spki = subject_public_key_info(#'AlgorithmIdentifier'{algorithm = ?'rsaEncryption',
280                                                          parameters =?DER_NULL}, KeyDer),
281    pem_entry_encode('SubjectPublicKeyInfo', Spki);
282pem_entry_encode('SubjectPublicKeyInfo',
283                 {DsaInt, Params=#'Dss-Parms'{}}) when is_integer(DsaInt) ->
284    KeyDer = der_encode('DSAPublicKey', DsaInt),
285    ParamDer = der_encode('DSAParams', {params, Params}),
286    Spki = subject_public_key_info(#'AlgorithmIdentifier'{algorithm =?'id-dsa',
287                                                          parameters = ParamDer},
288                                   KeyDer),
289    pem_entry_encode('SubjectPublicKeyInfo', Spki);
290pem_entry_encode('SubjectPublicKeyInfo',
291		 {#'ECPoint'{point = Key}, {namedCurve, ?'id-Ed25519' = ID}}) when is_binary(Key)->
292    Spki = subject_public_key_info(#'AlgorithmIdentifier'{algorithm = ID}, Key),
293    pem_entry_encode('SubjectPublicKeyInfo', Spki);
294pem_entry_encode('SubjectPublicKeyInfo',
295		 {#'ECPoint'{point = Key}, {namedCurve, ?'id-Ed448' = ID}}) when is_binary(Key)->
296    Spki = subject_public_key_info(#'AlgorithmIdentifier'{algorithm = ID}, Key),
297    pem_entry_encode('SubjectPublicKeyInfo', Spki);
298pem_entry_encode('SubjectPublicKeyInfo',
299		 {#'ECPoint'{point = Key}, ECParam}) when is_binary(Key)->
300    Params = der_encode('EcpkParameters',ECParam),
301    Spki = subject_public_key_info(#'AlgorithmIdentifier'{algorithm =?'id-ecPublicKey',
302                                                          parameters = Params},
303                                   Key),
304    pem_entry_encode('SubjectPublicKeyInfo', Spki);
305pem_entry_encode(Asn1Type, Entity)  when is_atom(Asn1Type) ->
306    Der = der_encode(Asn1Type, Entity),
307    {Asn1Type, Der, not_encrypted}.
308
309-spec pem_entry_encode(Asn1Type, Entity, InfoPwd) ->
310                              pem_entry() when Asn1Type :: pki_asn1_type(),
311                                               Entity :: term(),
312                                               InfoPwd :: {CipherInfo,Password},
313                                               CipherInfo :: cipher_info(),
314                                               Password :: string() .
315pem_entry_encode(Asn1Type, Entity, {{Cipher, #'PBES2-params'{}} = CipherInfo,
316				    Password}) when is_atom(Asn1Type) andalso
317						    is_list(Password) andalso
318						    is_list(Cipher) ->
319    do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password);
320pem_entry_encode(Asn1Type, Entity, {{Cipher,
321 				     {#'PBEParameter'{}, _}} = CipherInfo,
322 				    Password}) when is_atom(Asn1Type) andalso
323 						    is_list(Password) andalso
324 						    is_list(Cipher) ->
325    do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password);
326pem_entry_encode(Asn1Type, Entity, {{Cipher, Salt} = CipherInfo,
327				    Password}) when is_atom(Asn1Type) andalso
328						    is_list(Password) andalso
329						    is_list(Cipher) andalso
330						    is_binary(Salt) andalso
331						    ((erlang:byte_size(Salt) == 8) or
332						     (erlang:byte_size(Salt) == 16)) ->
333    do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password).
334
335%%--------------------------------------------------------------------
336-spec der_decode(Asn1Type, Der) -> Entity when Asn1Type :: asn1_type(),
337                                               Der :: der_encoded(),
338                                               Entity :: term().
339%%
340%% Description: Decodes a public key asn1 der encoded entity.
341%%--------------------------------------------------------------------
342der_decode(Asn1Type, Der) when (((Asn1Type == 'PrivateKeyInfo')
343                                 orelse
344                                   (Asn1Type == 'EncryptedPrivateKeyInfo'))
345                                andalso is_binary(Der)) ->
346    try
347	{ok, Decoded} = 'PKCS-FRAME':decode(Asn1Type, Der),
348	der_priv_key_decode(Decoded)
349    catch
350	error:{badmatch, {error, _}} = Error ->
351            handle_pkcs_frame_error(Asn1Type, Der, Error)
352    end;
353
354der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) ->
355    try
356	{ok, Decoded} = 'OTP-PUB-KEY':decode(Asn1Type, Der),
357	Decoded
358    catch
359	error:{badmatch, {error, _}} = Error ->
360	    erlang:error(Error)
361    end.
362
363handle_pkcs_frame_error('PrivateKeyInfo', Der, _) ->
364    try
365	{ok, Decoded} = 'PKCS-FRAME':decode('OneAsymmetricKey', Der),
366	der_priv_key_decode(Decoded)
367    catch
368	error:{badmatch, {error, _}} = Error ->
369	    erlang:error(Error)
370    end;
371handle_pkcs_frame_error(_, _, Error) ->
372    erlang:error(Error).
373
374der_priv_key_decode(#'PrivateKeyInfo'{version = v1,
375                                      privateKeyAlgorithm =
376                                          #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-ecPublicKey',
377                                                                                parameters = {asn1_OPENTYPE, Parameters}},
378                                      privateKey = PrivKey}) ->
379    EcPrivKey = der_decode('ECPrivateKey', PrivKey),
380    EcPrivKey#'ECPrivateKey'{parameters = der_decode('EcpkParameters', Parameters)};
381der_priv_key_decode(#'PrivateKeyInfo'{version = v1,
382                                      privateKeyAlgorithm =#'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = CurveOId},
383                                      privateKey = CurvePrivKey}) when
384      CurveOId == ?'id-Ed25519'orelse
385      CurveOId == ?'id-Ed448' ->
386    PrivKey = der_decode('CurvePrivateKey', CurvePrivKey),
387    #'ECPrivateKey'{version = 1, parameters = {namedCurve, CurveOId}, privateKey = PrivKey};
388der_priv_key_decode(#'OneAsymmetricKey'{
389                       privateKeyAlgorithm = #'OneAsymmetricKey_privateKeyAlgorithm'{algorithm = CurveOId},
390                       privateKey = CurvePrivKey,
391                       attributes = Attr,
392                       publicKey = PubKey}) when
393      CurveOId == ?'id-Ed25519'orelse
394      CurveOId == ?'id-Ed448' ->
395    PrivKey = der_decode('CurvePrivateKey', CurvePrivKey),
396    #'ECPrivateKey'{version = 2, parameters = {namedCurve, CurveOId}, privateKey = PrivKey,
397                    attributes = Attr,
398                    publicKey = PubKey};
399der_priv_key_decode({'PrivateKeyInfo', v1,
400	{'PrivateKeyInfo_privateKeyAlgorithm', ?'rsaEncryption', _}, PrivKey, _}) ->
401	der_decode('RSAPrivateKey', PrivKey);
402der_priv_key_decode({'PrivateKeyInfo', v1,
403                     {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-RSASSA-PSS',
404                      {asn1_OPENTYPE, Parameters}}, PrivKey, _}) ->
405    Key = der_decode('RSAPrivateKey', PrivKey),
406    Params = der_decode('RSASSA-PSS-params', Parameters),
407    {Key, Params};
408der_priv_key_decode(#'PrivateKeyInfo'{version = v1,
409                                      privateKeyAlgorithm = #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa',
410                                                                                                  parameters =
411                                                                                                      {asn1_OPENTYPE, Parameters}},
412                                      privateKey = PrivKey}) ->
413    {params, #'Dss-Parms'{p=P, q=Q, g=G}} = der_decode('DSAParams', Parameters),
414    X = der_decode('Prime-p', PrivKey),
415    #'DSAPrivateKey'{p=P, q=Q, g=G, x=X};
416der_priv_key_decode(PKCS8Key) ->
417    PKCS8Key.
418
419%%--------------------------------------------------------------------
420-spec der_encode(Asn1Type, Entity) -> Der when Asn1Type :: asn1_type(),
421                                               Entity :: term(),
422                                               Der :: binary() .
423%%
424%% Description: Encodes a public key entity with asn1 DER encoding.
425%%--------------------------------------------------------------------
426der_encode('PrivateKeyInfo', #'DSAPrivateKey'{p=P, q=Q, g=G, x=X}) ->
427    Params = der_encode('Dss-Parms', #'Dss-Parms'{p=P, q=Q, g=G}),
428    Alg =  #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa',
429                                                 parameters =
430                                                     {asn1_OPENTYPE, Params}},
431    Key = der_encode('Prime-p', X),
432    der_encode('PrivateKeyInfo',
433               #'PrivateKeyInfo'{version = v1,
434                                 privateKeyAlgorithm = Alg,
435                                 privateKey = Key});
436der_encode('PrivateKeyInfo', #'RSAPrivateKey'{} = PrivKey) ->
437    Parms = ?DER_NULL,
438    Alg = #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'rsaEncryption',
439                                                parameters = {asn1_OPENTYPE, Parms}},
440    Key = der_encode('RSAPrivateKey', PrivKey),
441    der_encode('PrivateKeyInfo',
442               #'PrivateKeyInfo'{version = v1,
443                                 privateKeyAlgorithm = Alg,
444                                 privateKey = Key});
445der_encode('PrivateKeyInfo', {#'RSAPrivateKey'{} = PrivKey, Parameters}) ->
446    Params = der_encode('RSASSA-PSS-params', Parameters),
447    Alg = #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-RSASSA-PSS',
448                                                parameters =
449                                                    {asn1_OPENTYPE, Params}},
450    Key = der_encode('RSAPrivateKey', PrivKey),
451    der_encode('PrivateKeyInfo', #'PrivateKeyInfo'{version = v1,
452                                                   privateKeyAlgorithm = Alg,
453                                                   privateKey = Key});
454der_encode('PrivateKeyInfo', #'ECPrivateKey'{parameters = {namedCurve, CurveOId},
455                                             privateKey = Key}) when
456      CurveOId == ?'id-Ed25519' orelse
457      CurveOId == ?'id-Ed448' ->
458    CurvePrivKey = der_encode('CurvePrivateKey', Key),
459    Alg = #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = CurveOId},
460    der_encode('PrivateKeyInfo', #'PrivateKeyInfo'{version = v1,
461                                                   privateKeyAlgorithm = Alg,
462                                                   privateKey = CurvePrivKey});
463der_encode('PrivateKeyInfo', #'ECPrivateKey'{parameters = Parameters} = PrivKey) ->
464    Params = der_encode('EcpkParameters', Parameters),
465    Alg = #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-ecPublicKey',
466                                                parameters = {asn1_OPENTYPE, Params}},
467    Key = der_encode('ECPrivateKey', PrivKey#'ECPrivateKey'{parameters = asn1_NOVALUE}),
468    der_encode('PrivateKeyInfo',
469               #'PrivateKeyInfo'{version = v1,
470                                 privateKeyAlgorithm = Alg,
471                                 privateKey = Key});
472der_encode('OneAsymmetricKey', #'ECPrivateKey'{parameters = {namedCurve, CurveOId},
473                                               privateKey = Key,
474                                               attributes = Attr,
475                                               publicKey = PubKey}) when
476      CurveOId == ?'id-Ed25519' orelse
477      CurveOId == ?'id-Ed448' ->
478    CurvePrivKey = der_encode('CurvePrivateKey', Key),
479    Alg = #'OneAsymmetricKey_privateKeyAlgorithm'{algorithm = CurveOId},
480    der_encode('OneAsymmetricKey',
481               #'OneAsymmetricKey'{version = 1,
482                                   privateKeyAlgorithm = Alg,
483                                   privateKey = CurvePrivKey,
484                                   attributes = Attr,
485                                   publicKey = PubKey});
486der_encode('OneAsymmetricKey', #'ECPrivateKey'{parameters = {namedCurve, CurveOId},
487                                               privateKey = Key,
488                                               attributes = Attr,
489                                               publicKey = PubKey}) ->
490    Alg = #'OneAsymmetricKey_privateKeyAlgorithm'{algorithm = CurveOId},
491    der_encode('OneAsymmetricKey',
492               #'OneAsymmetricKey'{version = 1,
493                                   privateKeyAlgorithm = Alg,
494                                   privateKey = Key,
495                                   attributes = Attr,
496                                   publicKey = PubKey});
497der_encode(Asn1Type, Entity) when (Asn1Type == 'PrivateKeyInfo') orelse
498                                  (Asn1Type == 'OneAsymmetricKey') orelse
499				  (Asn1Type == 'EncryptedPrivateKeyInfo') ->
500     try
501         {ok, Encoded} = 'PKCS-FRAME':encode(Asn1Type, Entity),
502         Encoded
503     catch
504	error:{badmatch, {error, _}} = Error ->
505             erlang:error(Error)
506     end;
507der_encode(Asn1Type, Entity) when is_atom(Asn1Type) ->
508    try
509	{ok, Encoded} = 'OTP-PUB-KEY':encode(Asn1Type, Entity),
510	Encoded
511    catch
512	error:{badmatch, {error, _}} = Error ->
513	    erlang:error(Error)
514    end.
515
516%%--------------------------------------------------------------------
517-spec pkix_decode_cert(Cert, Type) ->
518          #'Certificate'{} | otp_cert()
519              when Cert :: der_cert(),
520                   Type :: plain | otp .
521%%
522%% Description: Decodes an asn1 der encoded pkix certificate. The otp
523%% option will use the customized asn1 specification OTP-PKIX.asn1 for
524%% decoding and also recursively decode most of the standard
525%% extensions.
526%% --------------------------------------------------------------------
527pkix_decode_cert(DerCert, plain)  when is_binary(DerCert) ->
528    der_decode('Certificate', DerCert);
529pkix_decode_cert(DerCert, otp) when is_binary(DerCert) ->
530    try
531	{ok, #'OTPCertificate'{}= Cert} =
532	    pubkey_cert_records:decode_cert(DerCert),
533	Cert
534    catch
535	error:{badmatch, {error, _}} = Error ->
536	    erlang:error(Error)
537    end.
538
539%%--------------------------------------------------------------------
540-spec pkix_encode(Asn1Type, Entity, Type) -> Der
541                                                 when Asn1Type :: asn1_type(),
542                                                      Entity :: term(),
543                                                      Type :: otp | plain,
544                                                      Der :: der_encoded() .
545%%
546%% Description: Der encodes a certificate or part of a certificate.
547%% This function must be used for encoding certificates or parts of certificates
548%% that are decoded with the otp format, whereas for the plain format this
549%% function will only call der_encode/2.
550%%--------------------------------------------------------------------
551pkix_encode(Asn1Type, Term, plain) when is_atom(Asn1Type) ->
552    der_encode(Asn1Type, Term);
553
554pkix_encode(Asn1Type, Term0, otp) when is_atom(Asn1Type) ->
555    Term = pubkey_cert_records:transform(Term0, encode),
556    der_encode(Asn1Type, Term).
557
558%%--------------------------------------------------------------------
559%%
560%% Description: Public key decryption using the private key.
561%%--------------------------------------------------------------------
562-spec decrypt_private(CipherText, Key) ->
563                             PlainText when CipherText :: binary(),
564                                            Key :: rsa_private_key(),
565                                            PlainText ::  binary() .
566decrypt_private(CipherText, Key) ->
567    decrypt_private(CipherText, Key, []).
568
569-spec decrypt_private(CipherText, Key, Options) ->
570                             PlainText when CipherText :: binary(),
571                                            Key :: rsa_private_key(),
572                                            Options :: crypto:pk_encrypt_decrypt_opts(),
573                                            PlainText ::  binary() .
574decrypt_private(CipherText,
575		#'RSAPrivateKey'{} = Key,
576		Options)
577  when is_binary(CipherText),
578       is_list(Options) ->
579    crypto:private_decrypt(rsa, CipherText, format_rsa_private_key(Key), default_options(Options)).
580
581%%--------------------------------------------------------------------
582%% Description: Public key decryption using the public key.
583%%--------------------------------------------------------------------
584-spec decrypt_public(CipherText, Key) ->
585			    PlainText
586                                when CipherText :: binary(),
587                                     Key :: rsa_public_key(),
588                                     PlainText :: binary() .
589decrypt_public(CipherText, Key) ->
590    decrypt_public(CipherText, Key, []).
591
592-spec decrypt_public(CipherText, Key, Options) ->
593			    PlainText
594                                when CipherText :: binary(),
595                                     Key :: rsa_public_key(),
596                                     Options :: crypto:pk_encrypt_decrypt_opts(),
597                                     PlainText :: binary() .
598decrypt_public(CipherText, #'RSAPublicKey'{modulus = N, publicExponent = E},
599	       Options) when is_binary(CipherText), is_list(Options)  ->
600    crypto:public_decrypt(rsa, CipherText,[E, N], default_options(Options)).
601
602%%--------------------------------------------------------------------
603%% Description: Public key encryption using the public key.
604%%--------------------------------------------------------------------
605-spec encrypt_public(PlainText, Key) ->
606			     CipherText
607                                 when  PlainText :: binary(),
608                                       Key :: rsa_public_key(),
609                                       CipherText :: binary() .
610encrypt_public(PlainText, Key) ->
611    encrypt_public(PlainText, Key, []).
612
613
614-spec encrypt_public(PlainText, Key, Options) ->
615			     CipherText
616                                 when  PlainText :: binary(),
617                                       Key :: rsa_public_key(),
618                                       Options :: crypto:pk_encrypt_decrypt_opts(),
619                                       CipherText :: binary() .
620encrypt_public(PlainText, #'RSAPublicKey'{modulus=N,publicExponent=E},
621	       Options) when is_binary(PlainText), is_list(Options) ->
622    crypto:public_encrypt(rsa, PlainText, [E,N], default_options(Options)).
623
624%%--------------------------------------------------------------------
625%%
626%% Description: Public key encryption using the private key.
627%%--------------------------------------------------------------------
628-spec encrypt_private(PlainText, Key) ->
629			     CipherText
630                                 when  PlainText :: binary(),
631                                       Key :: rsa_private_key(),
632                                       CipherText :: binary() .
633encrypt_private(PlainText, Key) ->
634    encrypt_private(PlainText, Key, []).
635
636
637-spec encrypt_private(PlainText, Key, Options) ->
638			     CipherText
639                                 when  PlainText :: binary(),
640                                       Key :: rsa_private_key(),
641                                       Options :: crypto:pk_encrypt_decrypt_opts(),
642                                       CipherText :: binary() .
643encrypt_private(PlainText,
644		#'RSAPrivateKey'{modulus = N, publicExponent = E,
645				 privateExponent = D} = Key,
646		Options)
647  when is_binary(PlainText),
648       is_integer(N), is_integer(E), is_integer(D),
649       is_list(Options) ->
650    crypto:private_encrypt(rsa, PlainText, format_rsa_private_key(Key), default_options(Options)).
651
652%%--------------------------------------------------------------------
653%% Description: List available group sizes among the pre-computed dh groups
654%%--------------------------------------------------------------------
655-spec dh_gex_group_sizes() -> [pos_integer()].
656dh_gex_group_sizes() ->
657    pubkey_ssh:dh_gex_group_sizes().
658
659%%--------------------------------------------------------------------
660%% Description: Select a precomputed group
661%%--------------------------------------------------------------------
662-spec dh_gex_group(MinSize, SuggestedSize, MaxSize, Groups) ->
663                          {ok,{Size,Group}} | {error,term()}
664                              when MinSize :: pos_integer(),
665                                   SuggestedSize :: pos_integer(),
666                                   MaxSize :: pos_integer(),
667                                   Groups :: undefined | [{Size,[Group]}],
668                                   Size :: pos_integer(),
669                                   Group :: {G,P},
670                                   G :: pos_integer(),
671                                   P :: pos_integer() .
672dh_gex_group(Min, N, Max, Groups) ->
673    pubkey_ssh:dh_gex_group(Min, N, Max, Groups).
674
675%%--------------------------------------------------------------------
676%% Description: Generate a new key pair
677%%--------------------------------------------------------------------
678-spec generate_key(DHparams | ECparams | RSAparams) ->
679                          DHkeys | ECkey | RSAkey
680                              when DHparams :: #'DHParameter'{},
681                                   DHkeys :: {PublicDH::binary(), PrivateDH::binary()},
682                                   ECparams :: ecpk_parameters_api(),
683                                   ECkey :: #'ECPrivateKey'{},
684                                   RSAparams :: {rsa, Size, PubExp},
685                                   Size::pos_integer(),
686                                   PubExp::pos_integer(),
687                                   RSAkey :: #'RSAPrivateKey'{} .
688
689generate_key(#'DHParameter'{prime = P, base = G}) ->
690    crypto:generate_key(dh, [P, G]);
691generate_key({namedCurve, _} = Params) ->
692    ec_generate_key(Params);
693generate_key({ecParameters, _} = Params) ->
694    ec_generate_key(Params);
695generate_key(#'ECParameters'{} = Params) ->
696    ec_generate_key(Params);
697generate_key({rsa, ModulusSize, PublicExponent}) ->
698    case crypto:generate_key(rsa, {ModulusSize,PublicExponent}) of
699        {[E, N], [E, N, D, P, Q, D_mod_P_1, D_mod_Q_1, InvQ_mod_P]} ->
700            Nint = crypto:bytes_to_integer(N),
701            Eint = crypto:bytes_to_integer(E),
702            #'RSAPrivateKey'{version = 'two-prime', % Two-factor (I guess since otherPrimeInfos is not given)
703                             modulus = Nint,
704                             publicExponent = Eint,
705                             privateExponent = crypto:bytes_to_integer(D),
706                             prime1 = crypto:bytes_to_integer(P),
707                             prime2 = crypto:bytes_to_integer(Q),
708                             exponent1 = crypto:bytes_to_integer(D_mod_P_1),
709                             exponent2 = crypto:bytes_to_integer(D_mod_Q_1),
710                             coefficient = crypto:bytes_to_integer(InvQ_mod_P)};
711
712        {[E, N], [E, N, D]} -> % FIXME: what to set the other fields in #'RSAPrivateKey'?
713                               % Answer: Miller [Mil76]
714                               %   G.L. Miller. Riemann's hypothesis and tests for primality.
715                               %   Journal of Computer and Systems Sciences,
716                               %   13(3):300-307,
717                               %   1976.
718            Nint = crypto:bytes_to_integer(N),
719            Eint = crypto:bytes_to_integer(E),
720            #'RSAPrivateKey'{version = 'two-prime', % Two-factor (I guess since otherPrimeInfos is not given)
721                              modulus = Nint,
722                              publicExponent = Eint,
723                              privateExponent = crypto:bytes_to_integer(D),
724                              prime1 = '?',
725                              prime2 = '?',
726                              exponent1 = '?',
727                              exponent2 = '?',
728                              coefficient = '?'};
729
730        Other ->
731            Other
732    end.
733
734%%--------------------------------------------------------------------
735%% Description: Compute shared secret
736%%--------------------------------------------------------------------
737-spec compute_key(OthersECDHkey, MyECDHkey) ->
738                         SharedSecret
739                             when OthersECDHkey :: #'ECPoint'{},
740                                  MyECDHkey :: #'ECPrivateKey'{},
741                                  SharedSecret :: binary().
742compute_key(#'ECPoint'{point = Point}, #'ECPrivateKey'{privateKey = PrivKey,
743						       parameters = {namedCurve, Curve} = Param})
744  when (Curve == ?'id-X25519') orelse
745       (Curve == ?'id-X448') ->
746    ECCurve = ec_curve_spec(Param),
747    crypto:compute_key(eddh, Point, PrivKey, ECCurve);
748compute_key(#'ECPoint'{point = Point}, #'ECPrivateKey'{privateKey = PrivKey,
749						       parameters = Param}) ->
750    ECCurve = ec_curve_spec(Param),
751    crypto:compute_key(ecdh, Point, PrivKey, ECCurve).
752
753-spec compute_key(OthersDHkey, MyDHkey, DHparms) ->
754                         SharedSecret
755                             when OthersDHkey :: crypto:dh_public(), % Was: binary(),
756                                  MyDHkey :: crypto:dh_private(), % Was: binary(),
757                                  DHparms ::  #'DHParameter'{},
758                                  SharedSecret :: binary().
759compute_key(PubKey, PrivKey, #'DHParameter'{prime = P, base = G}) ->
760    crypto:compute_key(dh, PubKey, PrivKey, [P, G]).
761
762%%--------------------------------------------------------------------
763-spec pkix_sign_types(AlgorithmId) ->
764                             {DigestType, SignatureType}
765                                 when AlgorithmId :: oid(),
766                                      %% Relevant dsa digest type is a subset of rsa_digest_type()
767                                      DigestType :: crypto:rsa_digest_type() | none,
768                                      SignatureType :: rsa | dsa | ecdsa .
769%% Description:
770%%--------------------------------------------------------------------
771pkix_sign_types(?sha1WithRSAEncryption) ->
772    {sha, rsa};
773pkix_sign_types(?'sha-1WithRSAEncryption') ->
774    {sha, rsa};
775pkix_sign_types(?sha224WithRSAEncryption) ->
776    {sha224, rsa};
777pkix_sign_types(?sha256WithRSAEncryption) ->
778    {sha256, rsa};
779pkix_sign_types(?sha384WithRSAEncryption) ->
780    {sha384, rsa};
781pkix_sign_types(?sha512WithRSAEncryption) ->
782    {sha512, rsa};
783pkix_sign_types(?md5WithRSAEncryption) ->
784    {md5, rsa};
785pkix_sign_types(?'id-dsa-with-sha1') ->
786    {sha, dsa};
787pkix_sign_types(?'id-dsaWithSHA1') ->
788    {sha, dsa};
789pkix_sign_types(?'id-dsa-with-sha224') ->
790    {sha224, dsa};
791pkix_sign_types(?'id-dsa-with-sha256') ->
792    {sha256, dsa};
793pkix_sign_types(?'ecdsa-with-SHA1') ->
794    {sha, ecdsa};
795pkix_sign_types(?'ecdsa-with-SHA256') ->
796    {sha256, ecdsa};
797pkix_sign_types(?'ecdsa-with-SHA384') ->
798    {sha384, ecdsa};
799pkix_sign_types(?'ecdsa-with-SHA512') ->
800    {sha512, ecdsa};
801pkix_sign_types(?'id-Ed25519') ->
802    {none, eddsa};
803pkix_sign_types(?'id-Ed448') ->
804    {none, eddsa}.
805
806%%--------------------------------------------------------------------
807-spec pkix_hash_type(HashOid::oid()) -> DigestType:: md5 | crypto:sha1() | crypto:sha2().
808
809pkix_hash_type(?'id-sha1') ->
810    sha;
811pkix_hash_type(?'id-sha512') ->
812    sha512;
813pkix_hash_type(?'id-sha384') ->
814    sha384;
815pkix_hash_type(?'id-sha256') ->
816    sha256;
817pkix_hash_type('id-sha224') ->
818    sha224;
819pkix_hash_type('id-md5') ->
820    md5.
821
822%%--------------------------------------------------------------------
823%% Description: Create digital signature.
824%%--------------------------------------------------------------------
825-spec sign(Msg, DigestType, Key) ->
826                  Signature when Msg ::  binary() | {digest,binary()},
827                                 DigestType :: digest_type(),
828                                 Key :: private_key() | ed_legacy_privkey(),
829                                 Signature :: binary() .
830sign(DigestOrPlainText, DigestType, Key) ->
831    sign(DigestOrPlainText, DigestType, Key, []).
832
833-spec sign(Msg, DigestType, Key, Options) ->
834                  Signature when Msg ::  binary() | {digest,binary()},
835                                 DigestType :: digest_type(),
836                                 Key :: private_key() | ed_legacy_privkey(),
837                                 Options :: crypto:pk_sign_verify_opts(),
838                                 Signature :: binary() .
839sign(Digest, none, Key = #'DSAPrivateKey'{}, Options) when is_binary(Digest) ->
840    %% Backwards compatible
841    sign({digest, Digest}, sha, Key, Options);
842sign(DigestOrPlainText, DigestType, Key, Options) ->
843    case format_sign_key(Key) of
844	badarg ->
845	    erlang:error(badarg, [DigestOrPlainText, DigestType, Key, Options]);
846	{Algorithm, CryptoKey} ->
847	    crypto:sign(Algorithm, DigestType, DigestOrPlainText, CryptoKey, Options)
848    end.
849
850%%--------------------------------------------------------------------
851%% Description: Verifies a digital signature.
852%%--------------------------------------------------------------------
853-spec verify(Msg, DigestType, Signature, Key) ->
854                    boolean() when Msg :: binary() | {digest, binary()},
855                                   DigestType :: digest_type(),
856                                   Signature :: binary(),
857                                   Key :: public_key() | ed_legacy_pubkey().
858
859verify(DigestOrPlainText, DigestType, Signature, Key) ->
860    verify(DigestOrPlainText, DigestType, Signature, Key, []).
861
862-spec verify(Msg, DigestType, Signature, Key, Options) ->
863                    boolean() when Msg :: binary() | {digest, binary()},
864                                   DigestType :: digest_type(),
865                                   Signature :: binary(),
866                                   Key :: public_key() | ed_legacy_pubkey(),
867                                   Options :: crypto:pk_sign_verify_opts().
868
869verify(Digest, none, Signature, Key = {_, #'Dss-Parms'{}}, Options) when is_binary(Digest) ->
870    %% Backwards compatible
871    verify({digest, Digest}, sha, Signature, Key, Options);
872verify(DigestOrPlainText, DigestType, Signature, Key, Options) when is_binary(Signature) ->
873    case format_verify_key(Key) of
874	badarg ->
875	    erlang:error(badarg, [DigestOrPlainText, DigestType, Signature, Key, Options]);
876	{Algorithm, CryptoKey} ->
877	    crypto:verify(Algorithm, DigestType, DigestOrPlainText, Signature, CryptoKey, Options)
878    end;
879verify(_,_,_,_,_) ->
880    %% If Signature is a bitstring and not a binary we know already at this
881    %% point that the signature is invalid.
882    false.
883
884%%--------------------------------------------------------------------
885-spec pkix_dist_point(Cert) -> DistPoint when Cert :: cert(),
886                                              DistPoint :: #'DistributionPoint'{}.
887%% Description:  Creates a distribution point for CRLs issued by the same issuer as <c>Cert</c>.
888%%--------------------------------------------------------------------
889pkix_dist_point(OtpCert) when is_binary(OtpCert) ->
890    pkix_dist_point(pkix_decode_cert(OtpCert, otp));
891pkix_dist_point(OtpCert) ->
892    Issuer = public_key:pkix_normalize_name(
893	       pubkey_cert_records:transform(
894		 OtpCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.issuer, encode)),
895
896    TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
897    Extensions = pubkey_cert:extensions_list(TBSCert#'OTPTBSCertificate'.extensions),
898    AltNames = case pubkey_cert:select_extension(?'id-ce-issuerAltName', Extensions) of
899		   undefined ->
900		       [];
901		   #'Extension'{extnValue = Value} ->
902		       Value
903	       end,
904    Point = {fullName, [{directoryName, Issuer} | AltNames]},
905    #'DistributionPoint'{cRLIssuer = asn1_NOVALUE,
906			 reasons = asn1_NOVALUE,
907			 distributionPoint =  Point}.
908%%--------------------------------------------------------------------
909-spec pkix_dist_points(Cert) -> DistPoints when Cert :: cert(),
910                                                DistPoints :: [ #'DistributionPoint'{} ].
911%% Description:  Extracts distributionpoints specified in the certificates extensions.
912%%--------------------------------------------------------------------
913pkix_dist_points(OtpCert) when is_binary(OtpCert) ->
914    pkix_dist_points(pkix_decode_cert(OtpCert, otp));
915pkix_dist_points(OtpCert) ->
916    Value = pubkey_cert:distribution_points(OtpCert),
917    lists:foldl(fun(Point, Acc0) ->
918			DistPoint = pubkey_cert_records:transform(Point, decode),
919			[DistPoint | Acc0]
920		end,
921		[], Value).
922
923%%--------------------------------------------------------------------
924-spec pkix_match_dist_point(CRL, DistPoint) ->
925                                   boolean()
926                                       when CRL :: der_encoded() | #'CertificateList'{},
927                                            DistPoint :: #'DistributionPoint'{}.
928%% Description: Check whether the given distribution point matches
929%% the "issuing distribution point" of the CRL.
930%%--------------------------------------------------------------------
931pkix_match_dist_point(CRL, DistPoint) when is_binary(CRL) ->
932    pkix_match_dist_point(der_decode('CertificateList', CRL), DistPoint);
933pkix_match_dist_point(#'CertificateList'{},
934		      #'DistributionPoint'{distributionPoint = asn1_NOVALUE}) ->
935    %% No distribution point name specified - that's considered a match.
936    true;
937pkix_match_dist_point(#'CertificateList'{
938			 tbsCertList =
939			     #'TBSCertList'{
940				crlExtensions = Extensions}},
941		      #'DistributionPoint'{
942			 distributionPoint = {fullName, DPs}}) ->
943    case pubkey_cert:select_extension(?'id-ce-issuingDistributionPoint', Extensions) of
944	undefined ->
945	    %% If the CRL doesn't have an IDP extension, it
946	    %% automatically qualifies.
947	    true;
948	#'Extension'{extnValue = IDPValue} ->
949	    %% If the CRL does have an IDP extension, it must match
950	    %% the given DistributionPoint to be considered a match.
951	    IDPEncoded = der_decode('IssuingDistributionPoint', IDPValue),
952	    #'IssuingDistributionPoint'{distributionPoint = {fullName, IDPs}} =
953		pubkey_cert_records:transform(IDPEncoded, decode),
954	    pubkey_crl:match_one(IDPs, DPs)
955    end.
956
957%%--------------------------------------------------------------------
958-spec pkix_sign(Cert, Key) -> Der when Cert :: #'OTPTBSCertificate'{},
959                                       Key :: private_key(),
960                                       Der :: der_encoded() .
961%%
962%% Description: Sign a pkix x.509 certificate. Returns the corresponding
963%% der encoded 'Certificate'{}
964%%--------------------------------------------------------------------
965pkix_sign(#'OTPTBSCertificate'{signature =
966				   #'SignatureAlgorithm'{}
967			       = SigAlg} = TBSCert, Key) ->
968    Msg = pkix_encode('OTPTBSCertificate', TBSCert, otp),
969    {DigestType, _, Opts} = pubkey_cert:x509_pkix_sign_types(SigAlg),
970    Signature = sign(Msg, DigestType, format_pkix_sign_key(Key), Opts),
971    Cert = #'OTPCertificate'{tbsCertificate= TBSCert,
972			     signatureAlgorithm = SigAlg,
973			     signature = Signature
974			    },
975    pkix_encode('OTPCertificate', Cert, otp).
976
977%%--------------------------------------------------------------------
978-spec pkix_verify(Cert, Key) -> boolean() when Cert :: der_cert(),
979                                               Key :: public_key() .
980%%
981%% Description: Verify pkix x.509 certificate signature.
982%%--------------------------------------------------------------------
983pkix_verify(DerCert, {Key, #'Dss-Parms'{}} = DSAKey)
984  when is_binary(DerCert), is_integer(Key) ->
985    {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
986    verify(PlainText, DigestType, Signature, DSAKey);
987
988pkix_verify(DerCert,  #'RSAPublicKey'{} = RSAKey)
989  when is_binary(DerCert) ->
990    {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
991    verify(PlainText, DigestType, Signature, RSAKey);
992
993pkix_verify(DerCert,  {#'RSAPublicKey'{} = RSAKey, #'RSASSA-PSS-params'{} = Params})
994  when is_binary(DerCert) ->
995    {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
996    verify(PlainText, DigestType, Signature, RSAKey, rsa_opts(Params));
997
998pkix_verify(DerCert, Key = {#'ECPoint'{}, {namedCurve, Curve}}) when (Curve == ?'id-Ed25519'orelse
999                                                                      Curve == ?'id-Ed448') andalso is_binary(DerCert) ->
1000    case pubkey_cert:verify_data(DerCert) of
1001        {none = DigestType, PlainText, Signature} ->
1002            verify(PlainText, DigestType, Signature, Key);
1003        _ ->
1004            false
1005    end;
1006pkix_verify(DerCert, Key = {#'ECPoint'{}, _}) when is_binary(DerCert) ->
1007    case pubkey_cert:verify_data(DerCert) of
1008        {none, _, _} ->
1009            false;
1010        {DigestType, PlainText, Signature} ->
1011            verify(PlainText, DigestType, Signature, Key)
1012    end.
1013
1014%%--------------------------------------------------------------------
1015-spec pkix_crl_verify(CRL, Cert) -> boolean()
1016                                        when CRL  :: der_encoded() | #'CertificateList'{},
1017                                             Cert :: cert().
1018%%
1019%% Description: Verify that Cert is the CRL signer.
1020%%--------------------------------------------------------------------
1021pkix_crl_verify(CRL, Cert) when is_binary(CRL) ->
1022    pkix_crl_verify(der_decode('CertificateList', CRL), Cert);
1023pkix_crl_verify(CRL, Cert) when is_binary(Cert) ->
1024    pkix_crl_verify(CRL, pkix_decode_cert(Cert, otp));
1025pkix_crl_verify(#'CertificateList'{} = CRL, #'OTPCertificate'{} = Cert) ->
1026    TBSCert = Cert#'OTPCertificate'.tbsCertificate,
1027    PublicKeyInfo = TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
1028    PublicKey = PublicKeyInfo#'OTPSubjectPublicKeyInfo'.subjectPublicKey,
1029    AlgInfo = PublicKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm,
1030    PublicKeyParams = AlgInfo#'PublicKeyAlgorithm'.parameters,
1031    pubkey_crl:verify_crl_signature(CRL,
1032				    der_encode('CertificateList', CRL),
1033				    PublicKey, PublicKeyParams).
1034
1035%%--------------------------------------------------------------------
1036-spec pkix_is_issuer(CertorCRL, IssuerCert) ->
1037          boolean() when CertorCRL :: cert() | #'CertificateList'{},
1038                         IssuerCert :: cert().
1039%%
1040%% Description: Checks if <IssuerCert> issued <Cert>.
1041%%--------------------------------------------------------------------
1042pkix_is_issuer(Cert, IssuerCert)  when is_binary(Cert) ->
1043    OtpCert = pkix_decode_cert(Cert, otp),
1044    pkix_is_issuer(OtpCert, IssuerCert);
1045pkix_is_issuer(Cert, IssuerCert) when is_binary(IssuerCert) ->
1046    OtpIssuerCert = pkix_decode_cert(IssuerCert, otp),
1047    pkix_is_issuer(Cert, OtpIssuerCert);
1048pkix_is_issuer(#'OTPCertificate'{tbsCertificate = TBSCert},
1049	       #'OTPCertificate'{tbsCertificate = Candidate}) ->
1050    pubkey_cert:is_issuer(TBSCert#'OTPTBSCertificate'.issuer,
1051			  Candidate#'OTPTBSCertificate'.subject);
1052pkix_is_issuer(#'CertificateList'{tbsCertList = TBSCRL},
1053	       #'OTPCertificate'{tbsCertificate = Candidate}) ->
1054    pubkey_cert:is_issuer(Candidate#'OTPTBSCertificate'.subject,
1055			  pubkey_cert_records:transform(TBSCRL#'TBSCertList'.issuer, decode)).
1056
1057%%--------------------------------------------------------------------
1058-spec pkix_is_self_signed(Cert) -> boolean() when Cert::cert().
1059%%
1060%% Description: Checks if a Certificate is self signed.
1061%%--------------------------------------------------------------------
1062pkix_is_self_signed(#'OTPCertificate'{} = OTPCert) ->
1063    pubkey_cert:is_self_signed(OTPCert);
1064pkix_is_self_signed(Cert) when is_binary(Cert) ->
1065    OtpCert = pkix_decode_cert(Cert, otp),
1066    pkix_is_self_signed(OtpCert).
1067
1068%%--------------------------------------------------------------------
1069-spec pkix_is_fixed_dh_cert(Cert) -> boolean() when Cert::cert().
1070%%
1071%% Description: Checks if a Certificate is a fixed Diffie-Hellman Cert.
1072%%--------------------------------------------------------------------
1073pkix_is_fixed_dh_cert(#'OTPCertificate'{} = OTPCert) ->
1074    pubkey_cert:is_fixed_dh_cert(OTPCert);
1075pkix_is_fixed_dh_cert(Cert) when is_binary(Cert) ->
1076    OtpCert = pkix_decode_cert(Cert, otp),
1077    pkix_is_fixed_dh_cert(OtpCert).
1078
1079%%--------------------------------------------------------------------
1080-spec pkix_issuer_id(Cert, IssuedBy) ->
1081			    {ok, ID::cert_id()} | {error, Reason}
1082                                when Cert::cert(),
1083                                     IssuedBy :: self | other,
1084                                     Reason :: term() .
1085
1086%% Description: Returns the issuer id.
1087%%--------------------------------------------------------------------
1088pkix_issuer_id(#'OTPCertificate'{} = OtpCert, Signed) when (Signed == self) or
1089							   (Signed == other) ->
1090    pubkey_cert:issuer_id(OtpCert, Signed);
1091pkix_issuer_id(Cert, Signed) when is_binary(Cert) ->
1092    OtpCert = pkix_decode_cert(Cert, otp),
1093    pkix_issuer_id(OtpCert, Signed).
1094
1095%%--------------------------------------------------------------------
1096-spec pkix_subject_id(Cert) -> ID
1097              when Cert::cert(),
1098                   ID::cert_id() .
1099
1100%% Description: Returns the subject id.
1101%%--------------------------------------------------------------------
1102pkix_subject_id(#'OTPCertificate'{} = OtpCert) ->
1103    pubkey_cert:subject_id(OtpCert);
1104pkix_subject_id(Cert) when is_binary(Cert) ->
1105    OtpCert = pkix_decode_cert(Cert, otp),
1106    pkix_subject_id(OtpCert).
1107
1108%%--------------------------------------------------------------------
1109-spec pkix_crl_issuer(CRL) -> Issuer
1110               when CRL :: der_encoded() | #'CertificateList'{},
1111                    Issuer :: issuer_name() .
1112%% Description: Returns the issuer.
1113%%--------------------------------------------------------------------
1114pkix_crl_issuer(CRL) when is_binary(CRL) ->
1115    pkix_crl_issuer(der_decode('CertificateList', CRL));
1116pkix_crl_issuer(#'CertificateList'{} = CRL) ->
1117    pubkey_cert_records:transform(
1118      CRL#'CertificateList'.tbsCertList#'TBSCertList'.issuer, decode).
1119
1120%%--------------------------------------------------------------------
1121-spec pkix_normalize_name(Issuer) -> Normalized
1122                                         when Issuer :: issuer_name(),
1123                                              Normalized :: issuer_name() .
1124%%
1125%% Description: Normalizes a issuer name so that it can be easily
1126%%              compared to another issuer name.
1127%%--------------------------------------------------------------------
1128pkix_normalize_name(Issuer) ->
1129    pubkey_cert:normalize_general_name(Issuer).
1130
1131%%--------------------------------------------------------------------
1132-spec pkix_path_validation(Cert, CertChain, Options) ->
1133          {ok, {PublicKeyInfo, PolicyTree}} |
1134          {error, {bad_cert, Reason :: bad_cert_reason()}}
1135              when
1136      Cert :: cert() | atom(),
1137      CertChain :: [cert() | combined_cert()],
1138      Options  :: [{max_path_length, integer()} | {verify_fun, {fun(), term()}}],
1139      PublicKeyInfo :: public_key_info(),
1140      PolicyTree :: list().
1141
1142%% Description: Performs a basic path validation according to RFC 5280.
1143%%--------------------------------------------------------------------
1144pkix_path_validation(TrustedCert, CertChain, Options)
1145  when is_binary(TrustedCert) ->
1146
1147    OtpCert = pkix_decode_cert(TrustedCert, otp),
1148    pkix_path_validation(OtpCert, CertChain, Options);
1149pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options)
1150  when is_list(CertChain), is_list(Options) ->
1151    MaxPathDefault = length(CertChain),
1152    {VerifyFun, UserState0} =
1153	proplists:get_value(verify_fun, Options, ?DEFAULT_VERIFYFUN),
1154    try pubkey_cert:validate_time(TrustedCert, UserState0, VerifyFun) of
1155        UserState1 ->
1156            ValidationState = pubkey_cert:init_validation_state(TrustedCert,
1157                                                                MaxPathDefault,
1158                                                                [{verify_fun, {VerifyFun, UserState1}} |
1159                                                                 proplists:delete(verify_fun, Options)]),
1160            path_validation(CertChain, ValidationState)
1161    catch
1162        throw:{bad_cert, _} = Result ->
1163            {error, Result}
1164    end;
1165pkix_path_validation(PathErr, [Cert | Chain], Options0) when is_atom(PathErr)->
1166    {VerifyFun, Userstat0} =
1167	proplists:get_value(verify_fun, Options0, ?DEFAULT_VERIFYFUN),
1168    Otpcert = otp_cert(Cert),
1169    Reason = {bad_cert, PathErr},
1170    try VerifyFun(Otpcert, Reason, Userstat0) of
1171	{valid, Userstate} ->
1172	    Options = proplists:delete(verify_fun, Options0),
1173	    pkix_path_validation(Otpcert, Chain, [{verify_fun,
1174						   {VerifyFun, Userstate}}| Options]);
1175	{fail, UserReason} ->
1176	    {error, UserReason}
1177    catch
1178	_:_ ->
1179	    {error, Reason}
1180    end.
1181%--------------------------------------------------------------------
1182-spec pkix_crls_validate(OTPcertificate, DPandCRLs, Options) ->
1183                                CRLstatus when OTPcertificate :: #'OTPCertificate'{},
1184                                               DPandCRLs :: [DPandCRL],
1185                                               DPandCRL  :: {DP, {DerCRL, CRL}},
1186                                               DP :: #'DistributionPoint'{},
1187                                               DerCRL :: der_encoded(),
1188                                               CRL :: #'CertificateList'{},
1189                                               Options :: [{atom(),term()}],
1190                                               CRLstatus :: valid
1191                                                          | {bad_cert, BadCertReason},
1192                                               BadCertReason :: revocation_status_undetermined
1193                                                              | {revocation_status_undetermined, Reason::term()}
1194                                                              | {revoked, crl_reason()}.
1195
1196%% Description: Performs a CRL validation according to RFC 5280.
1197%%--------------------------------------------------------------------
1198pkix_crls_validate(OtpCert, [{_,_,_} |_] = DPAndCRLs, Options) ->
1199    pkix_crls_validate(OtpCert, DPAndCRLs, DPAndCRLs,
1200		       Options, pubkey_crl:init_revokation_state());
1201
1202pkix_crls_validate(OtpCert, DPAndCRLs0, Options) ->
1203    CallBack = proplists:get_value(update_crl, Options, fun(_, CurrCRL) ->
1204							       CurrCRL
1205						       end),
1206    DPAndCRLs = sort_dp_crls(DPAndCRLs0, CallBack),
1207    pkix_crls_validate(OtpCert, DPAndCRLs, DPAndCRLs,
1208		       Options, pubkey_crl:init_revokation_state()).
1209
1210%--------------------------------------------------------------------
1211-type referenceIDs() :: [referenceID()] .
1212-type referenceID() :: {uri_id | dns_id | ip | srv_id | atom() | oid(),  string()}
1213                     | {ip, inet:ip_address() | string()} .
1214
1215%% Description: Validates a hostname to RFC 6125
1216%%--------------------------------------------------------------------
1217-spec pkix_verify_hostname(Cert, ReferenceIDs) -> boolean()
1218                                                      when Cert :: cert(),
1219                                                           ReferenceIDs :: referenceIDs() .
1220pkix_verify_hostname(Cert, ReferenceIDs) ->
1221    pkix_verify_hostname(Cert, ReferenceIDs, []).
1222
1223-spec pkix_verify_hostname(Cert, ReferenceIDs, Options) ->
1224                                  boolean()
1225                                      when Cert :: cert(),
1226                                           ReferenceIDs :: referenceIDs(),
1227                                           Options :: [{match_fun | fail_callback | fqdn_fun, fun()}] .
1228
1229pkix_verify_hostname(BinCert, ReferenceIDs, Options)  when is_binary(BinCert) ->
1230    pkix_verify_hostname(pkix_decode_cert(BinCert,otp), ReferenceIDs, Options);
1231
1232pkix_verify_hostname(Cert = #'OTPCertificate'{tbsCertificate = TbsCert}, ReferenceIDs0, Opts) ->
1233    MatchFun = proplists:get_value(match_fun,     Opts, undefined),
1234    FailCB   = proplists:get_value(fail_callback, Opts, fun(_Cert) -> false end),
1235    FqdnFun  = proplists:get_value(fqdn_fun,      Opts, fun verify_hostname_extract_fqdn_default/1),
1236
1237    ReferenceIDs = [{T,to_string(V)} || {T,V} <- ReferenceIDs0],
1238    PresentedIDs =
1239	try lists:keyfind(?'id-ce-subjectAltName',
1240			  #'Extension'.extnID,
1241			  TbsCert#'OTPTBSCertificate'.extensions)
1242	of
1243	    #'Extension'{extnValue = ExtVals} ->
1244		[{T,to_string(V)} || {T,V} <- ExtVals];
1245	    false ->
1246		[]
1247	catch
1248	    _:_ -> []
1249	end,
1250    %% PresentedIDs example: [{dNSName,"ewstest.ericsson.com"}, {dNSName,"www.ericsson.com"}]}
1251    case PresentedIDs of
1252	[] ->
1253	    %% Fallback to CN-ids [rfc6125, ch6]
1254	    case TbsCert#'OTPTBSCertificate'.subject of
1255		{rdnSequence,RDNseq} ->
1256		    PresentedCNs =
1257			[{cn, to_string(V)}
1258			 || ATVs <- RDNseq, % RDNseq is list-of-lists
1259			    #'AttributeTypeAndValue'{type = ?'id-at-commonName',
1260						     value = {_T,V}} <- ATVs
1261						% _T = kind of string (teletexString etc)
1262			],
1263		    %% Example of PresentedCNs:  [{cn,"www.ericsson.se"}]
1264		    %% match ReferenceIDs to PresentedCNs
1265		    verify_hostname_match_loop(verify_hostname_fqnds(ReferenceIDs, FqdnFun),
1266					       PresentedCNs,
1267					       MatchFun, FailCB, Cert);
1268
1269		_ ->
1270		    false
1271	    end;
1272	_ ->
1273	    %% match ReferenceIDs to PresentedIDs
1274	    case verify_hostname_match_loop(ReferenceIDs, PresentedIDs,
1275					    MatchFun, FailCB, Cert) of
1276		false ->
1277		    %% Try to extract DNS-IDs from URIs etc
1278		    DNS_ReferenceIDs =
1279			[{dns_id,X} || X <- verify_hostname_fqnds(ReferenceIDs, FqdnFun)],
1280		    verify_hostname_match_loop(DNS_ReferenceIDs, PresentedIDs,
1281					       MatchFun, FailCB, Cert);
1282		true ->
1283		    true
1284	    end
1285    end.
1286
1287-spec pkix_verify_hostname_match_fun(Protocol) ->  Result when
1288      Protocol :: https,
1289      Result :: fun().
1290
1291
1292pkix_verify_hostname_match_fun(https) ->
1293    fun({dns_id,FQDN=[_|_]}, {dNSName,Name=[_|_]}) -> verify_hostname_match_wildcard(FQDN, Name);
1294       (_, _) -> default
1295    end.
1296
1297%%--------------------------------------------------------------------
1298-spec ssh_decode(SshBin, Type) ->
1299                        Decoded
1300                            when SshBin :: binary(),
1301                                 Type :: ssh2_pubkey | OtherType | InternalType,
1302                                 OtherType :: public_key | ssh_file(),
1303                                 InternalType :: new_openssh,
1304                                 Decoded :: Decoded_ssh2_pubkey
1305                                          | Decoded_OtherType,
1306                                 Decoded_ssh2_pubkey :: public_key() | ed_legacy_pubkey(),
1307                                 Decoded_OtherType :: [{public_key() | ed_legacy_pubkey(), Attributes}],
1308                                 Attributes :: [{atom(),term()}] .
1309%%
1310%% Description: Decodes a ssh file-binary. In the case of know_hosts
1311%% or auth_keys the binary may include one or more lines of the
1312%% file. Returns a list of public keys and their attributes, possible
1313%% attribute values depends on the file type represented by the
1314%% binary.
1315%%--------------------------------------------------------------------
1316ssh_decode(SshBin, Type) when is_binary(SshBin),
1317			      Type == public_key;
1318			      Type == rfc4716_public_key;
1319			      Type == openssh_public_key;
1320			      Type == auth_keys;
1321			      Type == known_hosts;
1322			      Type == ssh2_pubkey;
1323                              Type == new_openssh ->
1324    pubkey_ssh:decode(SshBin, Type).
1325
1326%%--------------------------------------------------------------------
1327-spec ssh_encode(InData, Type) ->
1328                        binary()
1329                            when Type :: ssh2_pubkey | OtherType,
1330                                 OtherType :: public_key | ssh_file(),
1331                                 InData :: InData_ssh2_pubkey | OtherInData,
1332                                 InData_ssh2_pubkey :: public_key() | ed_legacy_pubkey(),
1333                                 OtherInData :: [{Key,Attributes}],
1334                                 Key :: public_key() | ed_legacy_pubkey(),
1335                                 Attributes :: [{atom(),term()}] .
1336%%
1337%% Description: Encodes a list of ssh file entries (public keys and
1338%% attributes) to a binary. Possible attributes depends on the file
1339%% type.
1340%%--------------------------------------------------------------------
1341ssh_encode(Entries, Type) when is_list(Entries),
1342			       Type == rfc4716_public_key;
1343			       Type == openssh_public_key;
1344			       Type == auth_keys;
1345			       Type == known_hosts;
1346			       Type == ssh2_pubkey ->
1347    pubkey_ssh:encode(Entries, Type).
1348
1349%%--------------------------------------------------------------------
1350-spec ssh_curvename2oid(binary()) -> oid().
1351
1352%% Description: Converts from the ssh name of elliptic curves to
1353%% the OIDs.
1354%%--------------------------------------------------------------------
1355ssh_curvename2oid(<<"nistp256">>) ->  ?'secp256r1';
1356ssh_curvename2oid(<<"nistp384">>) ->  ?'secp384r1';
1357ssh_curvename2oid(<<"nistp521">>) ->  ?'secp521r1'.
1358
1359%%--------------------------------------------------------------------
1360-spec oid2ssh_curvename(oid()) -> binary().
1361
1362%% Description: Converts from elliptic curve OIDs to the ssh name.
1363%%--------------------------------------------------------------------
1364oid2ssh_curvename(?'secp256r1') -> <<"nistp256">>;
1365oid2ssh_curvename(?'secp384r1') -> <<"nistp384">>;
1366oid2ssh_curvename(?'secp521r1') -> <<"nistp521">>.
1367
1368%%--------------------------------------------------------------------
1369-spec ssh_hostkey_fingerprint(public_key()) -> string().
1370
1371ssh_hostkey_fingerprint(Key) ->
1372    sshfp_string(md5, public_key:ssh_encode(Key,ssh2_pubkey) ).
1373
1374
1375-spec ssh_hostkey_fingerprint( digest_type(),  public_key()) ->  string()
1376                           ; ([digest_type()], public_key())   -> [string()]
1377                           .
1378ssh_hostkey_fingerprint(HashAlgs, Key) when is_list(HashAlgs) ->
1379    EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
1380    [sshfp_full_string(HashAlg,EncKey) || HashAlg <- HashAlgs];
1381ssh_hostkey_fingerprint(HashAlg, Key) when is_atom(HashAlg) ->
1382    EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
1383    sshfp_full_string(HashAlg, EncKey).
1384
1385
1386sshfp_string(HashAlg, EncodedKey) ->
1387    %% Other HashAlgs than md5 will be printed with
1388    %% other formats than hextstr by
1389    %%    ssh-keygen -E <alg> -lf <file>
1390    fp_fmt(sshfp_fmt(HashAlg), crypto:hash(HashAlg, EncodedKey)).
1391
1392sshfp_full_string(HashAlg, EncKey) ->
1393    lists:concat([sshfp_alg_name(HashAlg),
1394		  [$: | sshfp_string(HashAlg, EncKey)]
1395		 ]).
1396
1397sshfp_alg_name(sha) -> "SHA1";
1398sshfp_alg_name(Alg) -> string:to_upper(atom_to_list(Alg)).
1399
1400sshfp_fmt(md5) -> hexstr;
1401sshfp_fmt(_) -> b64.
1402
1403fp_fmt(hexstr, Bin) ->
1404    lists:flatten(string:join([io_lib:format("~2.16.0b",[C1]) || <<C1>> <= Bin], ":"));
1405fp_fmt(b64, Bin) ->
1406    %% This function clause *seems* to be
1407    %%    [C || C<-base64:encode_to_string(Bin), C =/= $=]
1408    %% but I am not sure. Must be checked.
1409    B64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
1410    BitsInLast = 8*size(Bin) rem 6,
1411    Padding = (6-BitsInLast) rem 6, % Want BitsInLast = [1:5] to map to padding [5:1] and 0 -> 0
1412    [lists:nth(C+1,B64Chars) || <<C:6>> <= <<Bin/binary,0:Padding>> ].
1413
1414%%--------------------------------------------------------------------
1415-spec short_name_hash(Name) -> string() when Name :: issuer_name() .
1416
1417%% Description: Generates OpenSSL-style hash of a name.
1418%%--------------------------------------------------------------------
1419short_name_hash({rdnSequence, _Attributes} = Name) ->
1420    HashThis = encode_name_for_short_hash(Name),
1421    <<HashValue:32/little, _/binary>> = crypto:hash(sha, HashThis),
1422    string:to_lower(string:right(integer_to_list(HashValue, 16), 8, $0)).
1423
1424
1425%%--------------------------------------------------------------------
1426-spec pkix_test_data(ChainConf) -> TestConf when
1427      ChainConf :: #{server_chain:= chain_opts(),
1428                     client_chain:= chain_opts()} |
1429                   chain_opts(),
1430      TestConf :: test_config() | [conf_opt()].
1431
1432%% Description: Generates cert(s) and ssl configuration
1433%%--------------------------------------------------------------------
1434
1435pkix_test_data(#{client_chain := ClientChain0,
1436                 server_chain := ServerChain0}) ->
1437    Default = #{intermediates => []},
1438    ClientChain = maps:merge(Default, ClientChain0),
1439    ServerChain = maps:merge(Default, ServerChain0),
1440    pubkey_cert:gen_test_certs(#{client_chain => ClientChain,
1441                                 server_chain => ServerChain});
1442pkix_test_data(#{} = Chain) ->
1443    Default = #{intermediates => []},
1444    pubkey_cert:gen_test_certs(maps:merge(Default, Chain)).
1445
1446%%--------------------------------------------------------------------
1447-spec pkix_test_root_cert(Name, Options) ->
1448                                 RootCert
1449                                     when Name :: string(),
1450                                          Options :: [cert_opt()],
1451                                          RootCert :: test_root_cert().
1452%% Description: Generates a root cert suitable for pkix_test_data/1
1453%%--------------------------------------------------------------------
1454
1455pkix_test_root_cert(Name, Opts) ->
1456    pubkey_cert:root_cert(Name, Opts).
1457
1458%%--------------------------------------------------------------------
1459-spec pkix_ocsp_validate(Cert, IssuerCert, OcspRespDer,
1460                         ResponderCerts, NonceExt) -> valid | {bad_cert, Reason}
1461              when Cert:: cert(),
1462                   IssuerCert:: cert(),
1463                   OcspRespDer::der_encoded(),
1464                   ResponderCerts::[der_cert()],
1465                   NonceExt::undefined | binary(),
1466                   Reason::term().
1467
1468%% Description: Validate OCSP staple response
1469%%--------------------------------------------------------------------
1470pkix_ocsp_validate(DerCert, IssuerCert, OcspRespDer, ResponderCerts, NonceExt) when is_binary(DerCert) ->
1471    pkix_ocsp_validate(pkix_decode_cert(DerCert, otp),  IssuerCert, OcspRespDer, ResponderCerts, NonceExt);
1472pkix_ocsp_validate(Cert, DerIssuerCert, OcspRespDer, ResponderCerts, NonceExt) when is_binary(DerIssuerCert) ->
1473    pkix_ocsp_validate(Cert, pkix_decode_cert(DerIssuerCert, otp), OcspRespDer, ResponderCerts, NonceExt);
1474pkix_ocsp_validate(Cert, IssuerCert, OcspRespDer, ResponderCerts, NonceExt) ->
1475    case  ocsp_responses(OcspRespDer, ResponderCerts, NonceExt) of
1476        {ok, Responses} ->
1477            ocsp_status(Cert, IssuerCert, Responses);
1478        {error, Reason} ->
1479            {bad_cert, {revocation_status_undetermined, Reason}}
1480    end.
1481
1482%%--------------------------------------------------------------------
1483-spec ocsp_extensions(undefined | binary()) -> list().
1484%% Description: Get OCSP stapling extensions for request
1485%%--------------------------------------------------------------------
1486ocsp_extensions(Nonce) ->
1487    [Extn || Extn <- [pubkey_ocsp:get_nonce_extn(Nonce),
1488                      pubkey_ocsp:get_acceptable_response_types_extn()],
1489             erlang:is_record(Extn, 'Extension')].
1490
1491%%--------------------------------------------------------------------
1492-spec ocsp_responder_id(#'Certificate'{}) -> binary().
1493%%
1494%% Description: Get the OCSP responder ID der
1495%%--------------------------------------------------------------------
1496ocsp_responder_id(Cert) ->
1497    pubkey_ocsp:get_ocsp_responder_id(Cert).
1498
1499%%--------------------------------------------------------------------
1500%%% Internal functions
1501%%--------------------------------------------------------------------
1502default_options([]) ->
1503    [{rsa_padding, rsa_pkcs1_padding}];
1504default_options(Opts) ->
1505    case proplists:get_value(rsa_pad, Opts) of
1506        undefined ->
1507            case proplists:get_value(rsa_padding, Opts) of
1508                undefined ->
1509                    case lists:dropwhile(fun erlang:is_tuple/1, Opts) of
1510                        [Pad|_] ->
1511                            set_padding(Pad, Opts);
1512                        [] ->
1513                            set_padding(rsa_pkcs1_padding, Opts)
1514                    end;
1515                Pad ->
1516                    set_padding(Pad, Opts)
1517            end;
1518        Pad ->
1519            set_padding(Pad, Opts)
1520    end.
1521
1522set_padding(Pad, Opts) ->
1523    [{rsa_padding,Pad} | [{T,V} || {T,V} <- Opts,
1524                                   T =/= rsa_padding,
1525                                   T =/= rsa_pad]
1526    ].
1527
1528format_pkix_sign_key({#'RSAPrivateKey'{} = Key, _}) ->
1529    %% Params are handled in option arg
1530    Key;
1531format_pkix_sign_key(Key) ->
1532    Key.
1533format_sign_key(Key = #'RSAPrivateKey'{}) ->
1534    {rsa, format_rsa_private_key(Key)};
1535format_sign_key(#'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
1536    {dss, [P, Q, G, X]};
1537format_sign_key(#'ECPrivateKey'{privateKey = PrivKey, parameters = {namedCurve, Curve} = Param})
1538  when (Curve == ?'id-Ed25519') orelse (Curve == ?'id-Ed448')->
1539    ECCurve = ec_curve_spec(Param),
1540    {eddsa, [PrivKey, ECCurve]};
1541format_sign_key(#'ECPrivateKey'{privateKey = PrivKey, parameters = Param}) ->
1542    ECCurve = ec_curve_spec(Param),
1543    {ecdsa, [PrivKey, ECCurve]};
1544format_sign_key({ed_pri, Curve, _Pub, Priv}) ->
1545    {eddsa, [Priv,Curve]};
1546format_sign_key(_) ->
1547    badarg.
1548
1549format_verify_key(#'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) ->
1550    {rsa, [Exp, Mod]};
1551format_verify_key({#'ECPoint'{point = Point}, {namedCurve, Curve} = Param}) when (Curve == ?'id-Ed25519') orelse
1552                                                                                 (Curve == ?'id-Ed448') ->
1553    ECCurve = ec_curve_spec(Param),
1554    {eddsa, [Point, ECCurve]};
1555format_verify_key({#'ECPoint'{point = Point}, Param}) ->
1556    ECCurve = ec_curve_spec(Param),
1557    {ecdsa, [Point, ECCurve]};
1558format_verify_key({Key,  #'Dss-Parms'{p = P, q = Q, g = G}}) ->
1559    {dss, [P, Q, G, Key]};
1560format_verify_key({ed_pub, Curve, Key}) ->
1561    {eddsa, [Key,Curve]};
1562%% Convert private keys to public keys
1563format_verify_key(#'RSAPrivateKey'{modulus = Mod, publicExponent = Exp}) ->
1564    format_verify_key(#'RSAPublicKey'{modulus = Mod, publicExponent = Exp});
1565format_verify_key(#'ECPrivateKey'{parameters = Param, publicKey = {_, Point}}) ->
1566    format_verify_key({#'ECPoint'{point = Point}, Param});
1567format_verify_key(#'ECPrivateKey'{parameters = Param, publicKey = Point}) ->
1568    format_verify_key({#'ECPoint'{point = Point}, Param});
1569format_verify_key(#'DSAPrivateKey'{y=Y, p=P, q=Q, g=G}) ->
1570    format_verify_key({Y, #'Dss-Parms'{p=P, q=Q, g=G}});
1571format_verify_key(_) ->
1572    badarg.
1573
1574rsa_opts(#'RSASSA-PSS-params'{saltLength = SaltLen,
1575                              maskGenAlgorithm =
1576                                  #'MaskGenAlgorithm'{algorithm = ?'id-mgf1',
1577                                                      parameters = #'HashAlgorithm'{algorithm = HashAlgoOid}
1578                                                     }}) ->
1579    HashAlgo = pkix_hash_type(HashAlgoOid),
1580    [{rsa_padding, rsa_pkcs1_pss_padding},
1581     {rsa_pss_saltlen, SaltLen},
1582     {rsa_mgf1_md, HashAlgo}].
1583
1584do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password) ->
1585    Der = der_encode(Asn1Type, Entity),
1586    DecryptDer = pubkey_pem:cipher(Der, CipherInfo, Password),
1587    {Asn1Type, DecryptDer, CipherInfo}.
1588
1589do_pem_entry_decode({Asn1Type,_, _} = PemEntry, Password) ->
1590    Der = pubkey_pem:decipher(PemEntry, Password),
1591    der_decode(Asn1Type, Der).
1592
1593path_validation([], #path_validation_state{working_public_key_algorithm
1594					   = Algorithm,
1595					   working_public_key =
1596					   PublicKey,
1597					   working_public_key_parameters
1598					   = PublicKeyParams,
1599					   valid_policy_tree = Tree
1600					  }) ->
1601    {ok, {{Algorithm, PublicKey, PublicKeyParams}, Tree}};
1602
1603path_validation([DerCert | Rest], ValidationState = #path_validation_state{
1604				    max_path_length = Len}) when Len >= 0 ->
1605    try validate(DerCert,
1606		 ValidationState#path_validation_state{last_cert=Rest=:=[]}) of
1607	#path_validation_state{} = NewValidationState ->
1608	    path_validation(Rest, NewValidationState)
1609    catch
1610	throw:Reason ->
1611	    {error, Reason}
1612    end;
1613
1614path_validation([Cert | _] = Path,
1615		#path_validation_state{user_state = UserState0,
1616				       verify_fun = VerifyFun} =
1617		    ValidationState) ->
1618    Reason = {bad_cert, max_path_length_reached},
1619    OtpCert = otp_cert(Cert),
1620
1621    try VerifyFun(OtpCert,  Reason, UserState0) of
1622	{valid, UserState} ->
1623	    path_validation(Path,
1624			    ValidationState#path_validation_state{
1625			      max_path_length = 0,
1626			      user_state = UserState});
1627	{fail, _} ->
1628	    {error, Reason}
1629    catch
1630	_:_ ->
1631	    {error, Reason}
1632    end.
1633
1634validate(Cert, #path_validation_state{working_issuer_name = Issuer,
1635                                      working_public_key = Key,
1636                                      working_public_key_parameters =
1637                                          KeyParams,
1638                                      permitted_subtrees = Permit,
1639                                      excluded_subtrees = Exclude,
1640                                      last_cert = Last,
1641                                      user_state = UserState0,
1642                                      verify_fun = VerifyFun} =
1643	     ValidationState0) ->
1644
1645    OtpCert = otp_cert(Cert),
1646
1647    {ValidationState1, UserState1} =
1648	pubkey_cert:validate_extensions(OtpCert, ValidationState0, UserState0,
1649					VerifyFun),
1650
1651    %% We want the key_usage extension to be checked before we validate
1652    %% other things so that CRL validation errors will comply to standard
1653    %% test suite description
1654
1655    UserState2 = pubkey_cert:validate_time(OtpCert, UserState1, VerifyFun),
1656
1657    UserState3 = pubkey_cert:validate_issuer(OtpCert, Issuer, UserState2, VerifyFun),
1658
1659    UserState4 = pubkey_cert:validate_names(OtpCert, Permit, Exclude, Last,
1660					    UserState3, VerifyFun),
1661
1662    UserState5 = pubkey_cert:validate_signature(OtpCert, der_cert(Cert),
1663						Key, KeyParams, UserState4, VerifyFun),
1664    UserState = case Last of
1665		    false ->
1666			pubkey_cert:verify_fun(OtpCert, valid, UserState5, VerifyFun);
1667		    true ->
1668			pubkey_cert:verify_fun(OtpCert, valid_peer,
1669					       UserState5, VerifyFun)
1670		end,
1671
1672    ValidationState  =
1673	ValidationState1#path_validation_state{user_state = UserState},
1674
1675    pubkey_cert:prepare_for_next_cert(OtpCert, ValidationState).
1676
1677otp_cert(Der) when is_binary(Der) ->
1678    pkix_decode_cert(Der, otp);
1679otp_cert(#'OTPCertificate'{} = Cert) ->
1680    Cert;
1681otp_cert(#cert{otp = OtpCert}) ->
1682    OtpCert.
1683
1684der_cert(#'OTPCertificate'{} = Cert) ->
1685    pkix_encode('OTPCertificate', Cert, otp);
1686der_cert(Der) when is_binary(Der) ->
1687    Der;
1688der_cert(#cert{der = DerCert}) ->
1689    DerCert.
1690
1691pkix_crls_validate(_, [],_, Options, #revoke_state{details = Details}) ->
1692     case proplists:get_value(undetermined_details, Options, false) of
1693         false ->
1694             {bad_cert, revocation_status_undetermined};
1695         true ->
1696             {bad_cert, {revocation_status_undetermined, {bad_crls, format_details(Details)}}}
1697     end;
1698pkix_crls_validate(OtpCert, [{DP, CRL, DeltaCRL} | Rest],  All, Options, RevokedState0) ->
1699    CallBack = proplists:get_value(update_crl, Options, fun(_, CurrCRL) ->
1700							       CurrCRL
1701						       end),
1702    case pubkey_crl:fresh_crl(DP, CRL, CallBack) of
1703	{fresh, CRL} ->
1704	    do_pkix_crls_validate(OtpCert, [{DP, CRL, DeltaCRL} | Rest],
1705				  All, Options, RevokedState0);
1706	{fresh, NewCRL} ->
1707	    NewAll = [{DP, NewCRL, DeltaCRL} | All -- [{DP, CRL, DeltaCRL}]],
1708	    do_pkix_crls_validate(OtpCert, [{DP, NewCRL, DeltaCRL} | Rest],
1709				  NewAll, Options, RevokedState0);
1710	no_fresh_crl ->
1711	    pkix_crls_validate(OtpCert, Rest, All, Options, RevokedState0)
1712    end.
1713
1714do_pkix_crls_validate(OtpCert, [{DP, CRL, DeltaCRL} | Rest],  All, Options, RevokedState0) ->
1715    OtherDPCRLs = All -- [{DP, CRL, DeltaCRL}],
1716    case pubkey_crl:validate(OtpCert, OtherDPCRLs, DP, CRL, DeltaCRL, Options, RevokedState0) of
1717	{undetermined, unrevoked, #revoke_state{details = Details}} when Rest == []->
1718            case proplists:get_value(undetermined_details, Options, false) of
1719                false ->
1720                    {bad_cert, revocation_status_undetermined};
1721                true ->
1722                    {bad_cert, {revocation_status_undetermined, {bad_crls, Details}}}
1723            end;
1724	{undetermined, unrevoked, RevokedState} when Rest =/= []->
1725	    pkix_crls_validate(OtpCert, Rest, All, Options, RevokedState);
1726	{finished, unrevoked} ->
1727	    valid;
1728	{finished, Status} ->
1729	    {bad_cert, Status}
1730    end.
1731
1732sort_dp_crls(DpsAndCrls, FreshCB) ->
1733    sort_crls(maps:to_list(lists:foldl(fun group_dp_crls/2,
1734                                       #{},
1735                                       DpsAndCrls)),
1736              FreshCB, []).
1737
1738group_dp_crls({DP,CRL}, M) ->
1739    case M of
1740        #{DP := CRLs} -> M#{DP := [CRL|CRLs]};
1741        _ -> M#{DP => [CRL]}
1742    end.
1743
1744sort_crls([], _, Acc) ->
1745    Acc;
1746
1747sort_crls([{DP, AllCRLs} | Rest], FreshCB, Acc)->
1748    {DeltaCRLs, CRLs} = do_sort_crls(AllCRLs),
1749    DpsAndCRLs = combine(CRLs, DeltaCRLs, DP, FreshCB, []),
1750    sort_crls(Rest, FreshCB, DpsAndCRLs ++ Acc).
1751
1752do_sort_crls(CRLs) ->
1753    lists:partition(fun({_, CRL}) ->
1754			    pubkey_crl:is_delta_crl(CRL)
1755		    end, CRLs).
1756
1757combine([], _,_,_,Acc) ->
1758    Acc;
1759combine([{_, CRL} = Entry | CRLs], DeltaCRLs, DP, FreshCB, Acc) ->
1760    DeltaCRL = combine(CRL, DeltaCRLs),
1761    case pubkey_crl:fresh_crl(DP, DeltaCRL, FreshCB) of
1762	no_fresh_crl ->
1763	    combine(CRLs, DeltaCRLs, DP, FreshCB, [{DP, Entry, {undefined, undefined}} | Acc]);
1764	{fresh, NewDeltaCRL} ->
1765	    combine(CRLs, DeltaCRLs, DP, FreshCB, [{DP, Entry, NewDeltaCRL} | Acc])
1766    end.
1767
1768combine(CRL, DeltaCRLs) ->
1769    Deltas = lists:filter(fun({_,DeltaCRL}) ->
1770				  pubkey_crl:combines(CRL, DeltaCRL)
1771			  end, DeltaCRLs),
1772    case Deltas of
1773	[] ->
1774	    {undefined, undefined};
1775	[Delta] ->
1776	    Delta;
1777	[_,_|_] ->
1778	    Fun =
1779		fun({_, #'CertificateList'{tbsCertList = FirstTBSCRL}} = CRL1,
1780		    {_, #'CertificateList'{tbsCertList = SecondTBSCRL}} = CRL2) ->
1781			Time1 = pubkey_cert:time_str_2_gregorian_sec(
1782				  FirstTBSCRL#'TBSCertList'.thisUpdate),
1783			Time2 = pubkey_cert:time_str_2_gregorian_sec(
1784				  SecondTBSCRL#'TBSCertList'.thisUpdate),
1785			case Time1 > Time2 of
1786			      true ->
1787				CRL1;
1788			    false ->
1789				CRL2
1790			end
1791		end,
1792	    lists:foldl(Fun,  hd(Deltas), tl(Deltas))
1793    end.
1794
1795format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
1796					privateExponent = D,
1797					prime1 = P1, prime2 = P2,
1798					exponent1 = E1, exponent2 = E2,
1799					coefficient = C})
1800  when is_integer(N), is_integer(E), is_integer(D),
1801       is_integer(P1), is_integer(P2),
1802       is_integer(E1), is_integer(E2), is_integer(C) ->
1803   [E, N, D, P1, P2, E1, E2, C];
1804
1805format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
1806					privateExponent = D}) when is_integer(N),
1807								   is_integer(E),
1808								   is_integer(D) ->
1809   [E, N, D].
1810
1811-spec ec_generate_key(ecpk_parameters_api()) -> #'ECPrivateKey'{}.
1812ec_generate_key(Params) ->
1813    Curve = ec_curve_spec(Params),
1814    CurveType = ec_curve_type(Curve),
1815    Term = crypto:generate_key(CurveType, Curve),
1816    NormParams = ec_normalize_params(Params),
1817    ec_key(Term, NormParams).
1818
1819-spec ec_normalize_params(ecpk_parameters_api()) -> ecpk_parameters().
1820ec_normalize_params({namedCurve, Name}) when is_atom(Name) ->
1821	{namedCurve, pubkey_cert_records:namedCurves(Name)};
1822ec_normalize_params(#'ECParameters'{} = ECParams) ->
1823	{ecParameters, ECParams};
1824ec_normalize_params(Other) -> Other.
1825
1826-spec ec_curve_spec(ecpk_parameters_api()) -> term().
1827ec_curve_spec( #'ECParameters'{fieldID = #'FieldID'{fieldType = Type,
1828                                                    parameters = Params}, curve = PCurve, base = Base, order = Order, cofactor = CoFactor }) ->
1829    Field = format_field(pubkey_cert_records:supportedCurvesTypes(Type), Params),
1830    Curve = {PCurve#'Curve'.a, PCurve#'Curve'.b, none},
1831    {Field, Curve, Base, Order, CoFactor};
1832ec_curve_spec({ecParameters, ECParams}) ->
1833    ec_curve_spec(ECParams);
1834ec_curve_spec({namedCurve, OID}) when is_tuple(OID), is_integer(element(1,OID)) ->
1835    ec_curve_spec({namedCurve,  pubkey_cert_records:namedCurves(OID)});
1836ec_curve_spec({namedCurve, x25519 = Name}) ->
1837    Name;
1838ec_curve_spec({namedCurve, x448 = Name}) ->
1839    Name;
1840ec_curve_spec({namedCurve, ed25519 = Name}) ->
1841    Name;
1842ec_curve_spec({namedCurve, ed448 = Name}) ->
1843    Name;
1844ec_curve_spec({namedCurve, Name}) when is_atom(Name) ->
1845    crypto:ec_curve(Name).
1846
1847ec_curve_type(ed25519) ->
1848    eddsa;
1849ec_curve_type(ed448) ->
1850    eddsa;
1851ec_curve_type(x25519) ->
1852    eddh;
1853ec_curve_type(x448) ->
1854    eddh;
1855ec_curve_type(_) ->
1856    ecdh.
1857
1858format_field(characteristic_two_field = Type, Params0) ->
1859    #'Characteristic-two'{
1860       m = M,
1861       basis = BasisOid,
1862       parameters = Params} = der_decode('Characteristic-two', Params0),
1863    {Type, M, field_param_decode(BasisOid, Params)};
1864format_field(prime_field, Params0) ->
1865    Prime = der_decode('Prime-p', Params0),
1866    {prime_field, Prime}.
1867
1868field_param_decode(?'ppBasis', Params) ->
1869    #'Pentanomial'{k1 = K1, k2 = K2, k3 = K3} =
1870        der_decode('Pentanomial', Params),
1871    {ppbasis, K1, K2, K3};
1872field_param_decode(?'tpBasis', Params) ->
1873    K = der_decode('Trinomial', Params),
1874    {tpbasis, K};
1875field_param_decode(?'gnBasis', _) ->
1876    onbasis.
1877
1878-spec ec_key({PubKey::term(), PrivateKey::term()}, Params::ecpk_parameters()) -> #'ECPrivateKey'{}.
1879ec_key({PubKey, PrivateKey}, Params) ->
1880    #'ECPrivateKey'{version = 1,
1881		    privateKey = PrivateKey,
1882		    parameters = Params,
1883		    publicKey = PubKey}.
1884
1885encode_name_for_short_hash({rdnSequence, Attributes0}) ->
1886    Attributes = lists:map(fun normalise_attribute/1, Attributes0),
1887    {Encoded, _} = 'OTP-PUB-KEY':'enc_RDNSequence'(Attributes, []),
1888    Encoded.
1889
1890%% Normalise attribute for "short hash".  If the attribute value
1891%% hasn't been decoded yet, decode it so we can normalise it.
1892normalise_attribute([#'AttributeTypeAndValue'{
1893                        type = _Type,
1894                        value = Binary} = ATV]) when is_binary(Binary) ->
1895    case pubkey_cert_records:transform(ATV, decode) of
1896	#'AttributeTypeAndValue'{value = Binary} ->
1897	    %% Cannot decode attribute; return original.
1898	    [ATV];
1899	DecodedATV = #'AttributeTypeAndValue'{} ->
1900	    %% The new value will either be String or {Encoding,String}.
1901	    normalise_attribute([DecodedATV])
1902    end;
1903normalise_attribute([#'AttributeTypeAndValue'{
1904                        type = _Type,
1905                        value = {Encoding, String}} = ATV])
1906  when
1907      Encoding =:= utf8String;
1908      Encoding =:= printableString;
1909      Encoding =:= teletexString;
1910      Encoding =:= ia5String ->
1911    %% These string types all give us something that the unicode
1912    %% module understands.
1913    NewValue = normalise_attribute_value(String),
1914    [ATV#'AttributeTypeAndValue'{value = NewValue}];
1915normalise_attribute([#'AttributeTypeAndValue'{
1916                        type = _Type,
1917                        value = String} = ATV]) when is_list(String) ->
1918    %% A string returned by pubkey_cert_records:transform/2, for
1919    %% certain attributes that commonly have incorrect value types.
1920    NewValue = normalise_attribute_value(String),
1921    [ATV#'AttributeTypeAndValue'{value = NewValue}].
1922
1923normalise_attribute_value(String) ->
1924    Converted = unicode:characters_to_binary(String),
1925    NormalisedString = normalise_string(Converted),
1926    %% We can't use the encoding function for the actual type of the
1927    %% attribute, since some of them don't allow utf8Strings, which is
1928    %% the required encoding when creating the hash.
1929    {NewBinary, _} = 'OTP-PUB-KEY':'enc_X520CommonName'({utf8String, NormalisedString}, []),
1930    NewBinary.
1931
1932normalise_string(String) ->
1933    %% Normalise attribute values as required for "short hashes", as
1934    %% implemented by OpenSSL.
1935
1936    %% Remove ASCII whitespace from beginning and end.
1937    TrimmedLeft = re:replace(String, "^[\s\f\n\r\t\v]+", "", [unicode, global]),
1938    TrimmedRight = re:replace(TrimmedLeft, "[\s\f\n\r\t\v]+$", "", [unicode, global]),
1939    %% Convert multiple whitespace characters to a single space.
1940    Collapsed = re:replace(TrimmedRight, "[\s\f\n\r\t\v]+", "\s", [unicode, global]),
1941    %% Convert ASCII characters to lowercase
1942    Lower = ascii_to_lower(Collapsed),
1943    %% And we're done!
1944    Lower.
1945
1946ascii_to_lower(String) ->
1947    %% Can't use string:to_lower/1, because that changes Latin-1
1948    %% characters as well.
1949    << <<(if $A =< C, C =< $Z ->
1950                  C + ($a - $A);
1951             true ->
1952                  C
1953          end)>>
1954       ||
1955        <<C>> <= iolist_to_binary(String) >>.
1956
1957%%%----------------------------------------------------------------
1958%%% pkix_verify_hostname help functions
1959verify_hostname_extract_fqdn_default({dns_id,S}) ->
1960    S;
1961verify_hostname_extract_fqdn_default({uri_id,URI}) ->
1962    #{scheme := "https", host := Host} = uri_string:normalize(URI, [return_map]),
1963    Host.
1964
1965
1966verify_hostname_fqnds(L, FqdnFun) ->
1967    [E || E0 <- L,
1968	  E <- [try case FqdnFun(E0) of
1969			default -> verify_hostname_extract_fqdn_default(E0);
1970                        undefined -> undefined; % will make the "is_list(E)" test fail
1971			Other -> Other
1972		    end
1973		catch _:_-> undefined % will make the "is_list(E)" test fail
1974		end],
1975	  is_list(E),
1976	  E =/= "",
1977	  {error,einval} == inet:parse_address(E)
1978    ].
1979
1980
1981-define(srvName_OID, {1,3,6,1,4,1,434,2,2,1,37,0}).
1982
1983verify_hostname_match_default(Ref, Pres) ->
1984    verify_hostname_match_default0(to_lower_ascii(Ref), to_lower_ascii(Pres)).
1985
1986verify_hostname_match_default0(FQDN=[_|_], {cn,FQDN}) ->
1987    not lists:member($*, FQDN);
1988verify_hostname_match_default0(FQDN=[_|_], {cn,Name=[_|_]}) ->
1989    verify_hostname_match_wildcard(FQDN, Name);
1990verify_hostname_match_default0({dns_id,R}, {dNSName,P}) ->
1991    R==P;
1992verify_hostname_match_default0({uri_id,R}, {uniformResourceIdentifier,P}) ->
1993    R==P;
1994verify_hostname_match_default0({ip,R}, {iPAddress,P}) when length(P) == 4 ->
1995    %% IPv4
1996    try
1997        list_to_tuple(P)
1998            == if is_tuple(R), size(R)==4 -> R;
1999                  is_list(R) -> ok(inet:parse_ipv4strict_address(R))
2000               end
2001    catch
2002        _:_ ->
2003            false
2004    end;
2005
2006verify_hostname_match_default0({ip,R}, {iPAddress,P}) when length(P) == 16 ->
2007    %% IPv6. The length 16 is due to the certificate specification.
2008    try
2009        l16_to_tup(P)
2010            == if is_tuple(R), size(R)==8 -> R;
2011                  is_list(R) -> ok(inet:parse_ipv6strict_address(R))
2012               end
2013    catch
2014        _:_ ->
2015            false
2016    end;
2017verify_hostname_match_default0({srv_id,R}, {srvName,P}) ->
2018    R==P;
2019verify_hostname_match_default0({srv_id,R}, {?srvName_OID,P}) ->
2020    R==P;
2021verify_hostname_match_default0(_, _) ->
2022    false.
2023
2024
2025verify_hostname_match_wildcard(FQDN, Name) ->
2026    [F1|Fs] = string:tokens(to_lower_ascii(FQDN), "."),
2027    [N1|Ns] = string:tokens(to_lower_ascii(Name), "."),
2028    match_wild(F1,N1) andalso Fs==Ns.
2029
2030
2031ok({ok,X}) -> X.
2032
2033l16_to_tup(L) -> list_to_tuple(l16_to_tup(L, [])).
2034%%
2035l16_to_tup([A,B|T], Acc) -> l16_to_tup(T, [(A bsl 8) bor B | Acc]);
2036l16_to_tup([], Acc) -> lists:reverse(Acc).
2037
2038match_wild(A,     [$*|B]) -> match_wild_suffixes(A, B);
2039match_wild([C|A], [ C|B]) -> match_wild(A, B);
2040match_wild([],        []) -> true;
2041match_wild(_,          _) -> false.
2042
2043%% Match the parts after the only wildcard by comparing them from the end
2044match_wild_suffixes(A, B) -> match_wild_sfx(lists:reverse(A), lists:reverse(B)).
2045
2046match_wild_sfx([$*|_],      _) -> false; % Bad name (no wildcards alowed)
2047match_wild_sfx(_,      [$*|_]) -> false; % Bad pattern (no more wildcards alowed)
2048match_wild_sfx([A|Ar], [A|Br]) -> match_wild_sfx(Ar, Br);
2049match_wild_sfx(Ar,         []) -> not lists:member($*, Ar); % Chk for bad name (= wildcards)
2050match_wild_sfx(_,           _) -> false.
2051
2052
2053verify_hostname_match_loop(Refs0, Pres0, undefined, FailCB, Cert) ->
2054    Pres = lists:map(fun to_lower_ascii/1, Pres0),
2055    Refs = lists:map(fun to_lower_ascii/1, Refs0),
2056    lists:any(
2057      fun(R) ->
2058	      lists:any(fun(P) ->
2059                                verify_hostname_match_default(R,P) orelse FailCB(Cert)
2060			end, Pres)
2061      end, Refs);
2062verify_hostname_match_loop(Refs, Pres, MatchFun, FailCB, Cert) ->
2063    lists:any(
2064      fun(R) ->
2065	      lists:any(fun(P) ->
2066				(case MatchFun(R,P) of
2067				     default -> verify_hostname_match_default(R,P);
2068				     Bool -> Bool
2069				 end) orelse FailCB(Cert)
2070			end,
2071			Pres)
2072      end,
2073      Refs).
2074
2075
2076to_lower_ascii({ip,_}=X) -> X;
2077to_lower_ascii({iPAddress,_}=X) -> X;
2078to_lower_ascii(S) when is_list(S) -> lists:map(fun to_lower_ascii/1, S);
2079to_lower_ascii({T,S}) -> {T, to_lower_ascii(S)};
2080to_lower_ascii(C) when $A =< C,C =< $Z -> C + ($a-$A);
2081to_lower_ascii(C) -> C.
2082
2083to_string(S) when is_list(S) -> S;
2084to_string(B) when is_binary(B) -> binary_to_list(B);
2085to_string(X) -> X.
2086
2087format_details([]) ->
2088    no_relevant_crls;
2089format_details(Details) ->
2090    Details.
2091
2092ocsp_status(Cert, IssuerCert, Responses) ->
2093    case pubkey_ocsp:find_single_response(Cert, IssuerCert, Responses) of
2094        {ok, #'SingleResponse'{certStatus = CertStatus}} ->
2095            pubkey_ocsp:ocsp_status(CertStatus);
2096        {error, no_matched_response = Reason} ->
2097            {bad_cert, {revocation_status_undetermined, Reason}}
2098    end.
2099
2100ocsp_responses(OCSPResponseDer, ResponderCerts, Nonce) ->
2101    pubkey_ocsp:verify_ocsp_response(OCSPResponseDer,
2102                                     ResponderCerts, Nonce).
2103
2104subject_public_key_info(Alg, PubKey) ->
2105    #'OTPSubjectPublicKeyInfo'{algorithm = Alg, subjectPublicKey = PubKey}.
2106