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