Public Key
Public Key
Public Key
1.1 Introduction
1.1.1 Purpose
The Public Key application deals with public-key related file formats, digital signatures, and X-509 certificates. It is
a library application that provides encode/decode, sign/verify, encrypt/decrypt, and similar functionality. It does not
read or write files, it expects or returns file contents or partial file contents as binaries.
1.1.2 Prerequisites
It is assumed that the reader is familiar with the Erlang programming language and has a basic understanding of the
concepts of using public-keys and digital certificates.
1.2 Public-Key Records
This chapter briefly describes Erlang records derived from ASN.1 specifications used to handle public key
infrastructure. The scope is to describe the data types of each component, not the semantics. For information on the
semantics, refer to the relevant standards and RFCs linked in the sections below.
Use the following include directive to get access to the records and constant macros described in the following sections:
-include_lib("public_key/include/public_key.hrl").
| {dNSName, string()}
| {x400Address, string()}
| {directoryName, {rdnSequence, [#AttributeTypeAndValue'{}]}}
| {ediPartyName, special_string()}
| {ediPartyName, special_string(), special_string()}
| {uniformResourceIdentifier, string()}
| {iPAddress, string()}
| {registeredId, oid()}
| {otherName, term()}
special_string() =
{teletexString, string()}
| {printableString, string()}
| {universalString, string()}
| {utf8String, binary()}
| {bmpString, string()}
dist_reason() =
unused
| keyCompromise
| cACompromise
| affiliationChanged
| superseded
| cessationOfOperation
| certificateHold
| privilegeWithdrawn
| aACompromise
OID_macro() =
?OID_name()
OID_name() =
atom()
1.2.2 RSA
Erlang representation of Rivest-Shamir-Adleman cryptosystem (RSA) keys follows:
#'RSAPublicKey'{
modulus, % integer()
publicExponent % integer()
}.
#'RSAPrivateKey'{
version, % two-prime | multi
modulus, % integer()
publicExponent, % integer()
privateExponent, % integer()
prime1, % integer()
prime2, % integer()
exponent1, % integer()
exponent2, % integer()
coefficient, % integer()
otherPrimeInfos % [#OtherPrimeInfo{}] | asn1_NOVALUE
}.
#'OtherPrimeInfo'{
prime, % integer()
exponent, % integer()
coefficient % integer()
}.
#'RSASSA-PSS-params'{hashAlgorithm, % #'HashAlgorithm'{}},
maskGenAlgorithm, % #'MaskGenAlgorithm'{}},
saltLength, % integer(),
trailerField, % integer()
}.
#'HashAlgorithm'{algorithm, % oid()
parameters % defaults to asn1_NOVALUE
}.
#'MaskGenAlgorithm'{algorithm, % oid()
parameters, % defaults to asn1_NOVALUE
}.
1.2.3 DSA
Erlang representation of Digital Signature Algorithm (DSA) keys
#'DSAPrivateKey',{
version, % integer()
p, % integer()
q, % integer()
g, % integer()
y, % integer()
x % integer()
}.
#'Dss-Parms',{
p, % integer()
q, % integer()
g % integer()
}.
#'ECPrivateKey'{
version, % integer()
privateKey, % binary()
parameters, % {ecParameters, #'ECParameters'{}} |
% {namedCurve, Oid::tuple()} |
% {implicitlyCA, 'NULL'}
publicKey % bitstring()
}.
#'ECParameters'{
version, % integer()
fieldID, % #'FieldID'{}
curve, % #'Curve'{}
base, % binary()
order, % integer()
cofactor % integer()
}.
#'Curve'{
a, % binary()
b, % binary()
seed % bitstring() - optional
}.
#'FieldID'{
fieldType, % oid()
parameters % Depending on fieldType
}.
#'ECPoint'{
point % binary() - the public key
}.
#'Certificate'{
tbsCertificate, % #'TBSCertificate'{}
signatureAlgorithm, % #'AlgorithmIdentifier'{}
signature % bitstring()
}.
#'TBSCertificate'{
version, % v1 | v2 | v3
serialNumber, % integer()
signature, % #'AlgorithmIdentifier'{}
issuer, % {rdnSequence, [#AttributeTypeAndValue'{}]}
validity, % #'Validity'{}
subject, % {rdnSequence, [#AttributeTypeAndValue'{}]}
subjectPublicKeyInfo, % #'SubjectPublicKeyInfo'{}
issuerUniqueID, % binary() | asn1_novalue
subjectUniqueID, % binary() | asn1_novalue
extensions % [#'Extension'{}]
}.
#'AlgorithmIdentifier'{
algorithm, % oid()
parameters % der_encoded()
}.
#'OTPCertificate'{
tbsCertificate, % #'OTPTBSCertificate'{}
signatureAlgorithm, % #'SignatureAlgorithm'
signature % bitstring()
}.
#'OTPTBSCertificate'{
version, % v1 | v2 | v3
serialNumber, % integer()
signature, % #'SignatureAlgorithm'
issuer, % {rdnSequence, [#AttributeTypeAndValue'{}]}
validity, % #'Validity'{}
subject, % {rdnSequence, [#AttributeTypeAndValue'{}]}
subjectPublicKeyInfo, % #'OTPSubjectPublicKeyInfo'{}
issuerUniqueID, % binary() | asn1_novalue
subjectUniqueID, % binary() | asn1_novalue
extensions % [#'Extension'{}]
}.
#'SignatureAlgorithm'{
algorithm, % id_signature_algorithm()
parameters % asn1_novalue | #'Dss-Parms'{}
}.
id_signature_algorithm() = OID_macro()
The available OID names are as follows:
OID Name
id-dsa-with-sha1
md2WithRSAEncryption
md5WithRSAEncryption
sha1WithRSAEncryption
sha224WithRSAEncryption
sha256WithRSAEncryption
sha512WithRSAEncryption
ecdsa-with-SHA1
#'AttributeTypeAndValue'{
type, % id_attributes()
value % term()
}.
The attribute OID name atoms and their corresponding value types are as follows:
id-at-name special_string()
id-at-surname special_string()
id-at-givenName special_string()
id-at-initials special_string()
id-at-generationQualifier special_string()
id-at-commonName special_string()
id-at-localityName special_string()
id-at-stateOrProvinceName special_string()
id-at-organizationName special_string()
id-at-title special_string()
id-at-pseudonym special_string()
#'Validity'{
notBefore, % time()
notAfter % time()
}.
#'SubjectPublicKeyInfo'{
algorithm, % #AlgorithmIdentifier{}
subjectPublicKey % binary()
}.
#'SubjectPublicKeyInfoAlgorithm'{
algorithm, % id_public_key_algorithm()
parameters % public_key_params()
}.
OID Name
rsaEncryption
id-dsa
dhpublicnumber
id-keyExchangeAlgorithm
id-ecPublicKey
#'Extension'{
extnID, % id_extensions() | oid()
critical, % boolean()
extnValue % der_encoded()
}.
id_extensions() Standard Certificate Extensions, Private Internet Extensions, CRL Extensions and CRL Entry
Extensions.
id-ce-authorityKeyIdentifier #'AuthorityKeyIdentifier'{}
id-ce-subjectKeyIdentifier oid()
id-ce-keyUsage [key_usage()]
id-ce-privateKeyUsagePeriod #'PrivateKeyUsagePeriod'{}
id-ce-certificatePolicies #'PolicyInformation'{}
id-ce-policyMappings #'PolicyMappings_SEQOF'{}
id-ce-subjectAltName general_name()
id-ce-issuerAltName general_name()
id-ce-subjectDirectoryAttributes [#'Attribute'{}]
id-ce-basicConstraints #'BasicConstraints'{}
id-ce-nameConstraints #'NameConstraints'{}
id-ce-policyConstraints #'PolicyConstraints'{}
id-ce-extKeyUsage [id_key_purpose()]
id-ce-cRLDistributionPoints [#'DistributionPoint'{}]
id-ce-inhibitAnyPolicy integer()
id-ce-freshestCRL [#'DistributionPoint'{}]
Here:
key_usage()
=
digitalSignature
| nonRepudiation
| keyEncipherment
| dataEncipherment
| keyAgreement
| keyCertSign
| cRLSign
| encipherOnly
| decipherOnly
And for id_key_purpose():
OID Name
id-kp-serverAuth
id-kp-clientAuth
id-kp-codeSigning
id-kp-emailProtection
id-kp-timeStamping
id-kp-OCSPSigning
#'AuthorityKeyIdentifier'{
keyIdentifier, % oid()
authorityCertIssuer, % general_name()
authorityCertSerialNumber % integer()
}.
#'PrivateKeyUsagePeriod'{
notBefore, % general_time()
notAfter % general_time()
}.
#'PolicyInformation'{
policyIdentifier, % oid()
policyQualifiers % [#PolicyQualifierInfo{}]
}.
#'PolicyQualifierInfo'{
policyQualifierId, % oid()
qualifier % string() | #'UserNotice'{}
}.
#'UserNotice'{
noticeRef, % #'NoticeReference'{}
explicitText % string()
}.
#'NoticeReference'{
organization, % string()
noticeNumbers % [integer()]
}.
#'PolicyMappings_SEQOF'{
issuerDomainPolicy, % oid()
subjectDomainPolicy % oid()
}.
#'Attribute'{
type, % oid()
values % [der_encoded()]
}).
#'BasicConstraints'{
cA, % boolean()
pathLenConstraint % integer()
}).
#'NameConstraints'{
permittedSubtrees, % [#'GeneralSubtree'{}]
excludedSubtrees % [#'GeneralSubtree'{}]
}).
#'GeneralSubtree'{
base, % general_name()
minimum, % integer()
maximum % integer()
}).
#'PolicyConstraints'{
requireExplicitPolicy, % integer()
inhibitPolicyMapping % integer()
}).
#'DistributionPoint'{
distributionPoint, % {fullName, [general_name()]} | {nameRelativeToCRLIssuer,
[#AttributeTypeAndValue{}]}
reasons, % [dist_reason()]
cRLIssuer % [general_name()]
}).
id-pe-authorityInfoAccess [#'AccessDescription'{}]
id-pe-subjectInfoAccess [#'AccessDescription'{}]
#'AccessDescription'{
accessMethod, % oid()
accessLocation % general_name()
}).
#'CertificateList'{
tbsCertList, % #'TBSCertList{}
signatureAlgorithm, % #'AlgorithmIdentifier'{}
signature % bitstring()
}).
#'TBSCertList'{
version, % v2 (if defined)
signature, % #AlgorithmIdentifier{}
issuer, % {rdnSequence, [#AttributeTypeAndValue'{}]}
thisUpdate, % time()
nextUpdate, % time()
revokedCertificates, % [#'TBSCertList_revokedCertificates_SEQOF'{}]
crlExtensions % [#'Extension'{}]
}).
#'TBSCertList_revokedCertificates_SEQOF'{
userCertificate, % integer()
revocationDate, % timer()
crlEntryExtensions % [#'Extension'{}]
}).
CRL Extensions
The CRL extensions OID name atoms and their corresponding value types are as follows:
id-ce-authorityKeyIdentifier #'AuthorityKeyIdentifier{}
id-ce-cRLNumber integer()
id-ce-deltaCRLIndicator integer()
id-ce-issuingDistributionPoint #'IssuingDistributionPoint'{}
id-ce-freshestCRL [#'Distributionpoint'{}]
Here, the data type 'IssuingDistributionPoint' is represented as the following Erlang record:
#'IssuingDistributionPoint'{
distributionPoint, % {fullName, [general_name()]} | {nameRelativeToCRLIssuer,
[#AttributeTypeAndValue'{}]}
onlyContainsUserCerts, % boolean()
onlyContainsCACerts, % boolean()
onlySomeReasons, % [dist_reason()]
indirectCRL, % boolean()
onlyContainsAttributeCerts % boolean()
}).
id-ce-cRLReason crl_reason()
id-ce-holdInstructionCode oid()
id-ce-invalidityDate general_time()
id-ce-certificateIssuer general_name()
Here:
crl_reason()
=
unspecified
| keyCompromise
| cACompromise
| affiliationChanged
| superseded
| cessationOfOperation
| certificateHold
| removeFromCRL
| privilegeWithdrawn
| aACompromise
#'CertificationRequest'{
certificationRequestInfo #'CertificationRequestInfo'{},
signatureAlgorithm #'CertificationRequest_signatureAlgorithm'{}}.
signature bitstring()
}
#'CertificationRequestInfo'{
version atom(),
subject {rdnSequence, [#AttributeTypeAndValue'{}]} ,
subjectPKInfo #'CertificationRequestInfo_subjectPKInfo'{},
attributes [#'AttributePKCS-10' {}]
}
#'CertificationRequestInfo_subjectPKInfo'{
algorithm #'CertificationRequestInfo_subjectPKInfo_algorithm'{}
subjectPublicKey bitstring()
}
#'CertificationRequestInfo_subjectPKInfo_algorithm'{
algorithm = oid(),
parameters = der_encoded()
}
#'CertificationRequest_signatureAlgorithm'{
algorithm = oid(),
parameters = der_encoded()
}
#'AttributePKCS-10'{
type = oid(),
values = [der_encoded()]
}
1.3 Getting Started
This section describes examples of how to use the Public Key API. Keys and certificates used in the following sections
are generated only for testing the Public Key application.
Some shell printouts in the following examples are abbreviated for increased readability.
<text>
-----BEGIN <SOMETHING>-----
<Attribute> : <Value>
<Base64 encoded DER data>
-----END <SOMETHING>-----
<text>
A file can contain several BEGIN/END blocks. Text lines between blocks are ignored. Attributes, if present, are
ignored except for Proc-Type and DEK-Info, which are used when DER data is encrypted.
Note:
File handling is not done by the Public Key application.
The following PEM file has only one entry, a private DSA key:
The following PEM file has only one entry, a private RSA key:
2>[RSAEntry] = public_key:pem_decode(PemBin).
[{'RSAPrivateKey',<<224,108,117,203,152,40,15,77,128,126,
221,195,154,249,85,208,202,251,109,
119,120,57,29,89,19,9,...>>,
{"DES-EDE3-CBC",<<"kÙeø¼pµL">>}}]
X509 Certificates
The following is an example of X509 certificates:
extnID = {2,5,29,19},
critical = true,
extnValue = [48,3,1,1,255]},
#'Extension'{
extnID = {2,5,29,15},
critical = false,
extnValue = [3,2,1,6]},
#'Extension'{
extnID = {2,5,29,14},
critical = false,
extnValue = [4,20,27,217,65,152,6,30,142|...]},
#'Extension'{
extnID = {2,5,29,17},
critical = false,
extnValue = [48,24,129,22,112,101,116,101|...]}]},
signatureAlgorithm =
#'AlgorithmIdentifier'{
algorithm = {1,2,840,113549,1,1,5},
parameters = <<5,0>>},
signature =
<<163,186,7,163,216,152,63,47,154,234,139,73,154,96,120,
165,2,52,196,195,109,167,192,...>>}
Parts of certificates can be decoded with public_key:der_decode/2, using the ASN.1 type of that part.
However, an application-specific certificate extension requires application-specific ASN.1 decode/encode-functions.
In the recent example, the first value of rdnSequence is of ASN.1 type 'X520CommonName'. ({2,5,4,3}
= ?id-at-commonName):
public_key:der_decode('X520CommonName', <<19,8,101,114,108,97,110,103,67,65>>).
{printableString,"erlangCA"}
However, certificates can also be decoded using pkix_decode_cert/2, which can customize and recursively
decode standard parts of a certificate:
critical = true,
extnValue =
#'BasicConstraints'{
cA = true,pathLenConstraint = asn1_NOVALUE}},
#'Extension'{
extnID = {2,5,29,15},
critical = false,
extnValue = [keyCertSign,cRLSign]},
#'Extension'{
extnID = {2,5,29,14},
critical = false,
extnValue = [27,217,65,152,6,30,142,132,245|...]},
#'Extension'{
extnID = {2,5,29,17},
critical = false,
extnValue = [{rfc822Name,"peter@erix.ericsson.se"}]}]},
signatureAlgorithm =
#'SignatureAlgorithm'{
algorithm = {1,2,840,113549,1,1,5},
parameters = 'NULL'},
signature =
<<163,186,7,163,216,152,63,47,154,234,139,73,154,96,120,
165,2,52,196,195,109,167,192,...>>}
or:
• PublicKey = #'RSAPublicKey'{}
Then you can proceed as follows:
Encrypt with the private key:
Note:
You normally do only one of the encrypt or decrypt operations, and the peer does the other. This normaly used in
legacy applications as a primitive digital signature.
Note:
You normally do only one of the sign or verify operations, and the peer does the other.
It can be appropriate to calculate the message digest before calling sign or verify, and then use none as second
argument:
Digest = crypto:sha(Msg),
Signature = public_key:sign(Digest, none, PrivateKey),
true = public_key:verify(Digest, none, Signature, PublicKey),
is checked by the certificate issuer when the certificate is signed. So if the certificate is issued by a trusted root the
client could trust the host names signed in it.
There is a default hostname matching procedure defined in RFC 6125, section 6 as well as protocol
dependent variations defined in RFC 6125 appendix B. The default procedure is implemented in
public_key:pkix_verify_hostname/2,3. It is possible for a client to hook in modified rules using the options list.
Some terminology is needed: the certificate presents hostname(s) on which it is valid. Those are called Presented IDs.
The hostname(s) the client belives it connects to are called Reference IDs. The matching rules aims to verify that there
is at least one of the Reference IDs that matches one of the Presented IDs. If not, the verification fails.
The IDs contains normal fully qualified domain names like e.g foo.example.com, but IP addresses are not
recommended. The rfc describes why this is not recommended as well as security considerations about how to aquire
the Reference IDs.
Internationalized domain names are not supported.
The example Subject field has one C, two CN and one O part. It is only the CN (Common Name) that is used by
hostname verification. The two other (C and O) is not used here even when they contain a domain name like the O
part. The C and O parts are defined elsewhere and meaningful only for other functions.
In the example the Presented IDs are example.com as well as hostnames matching *.example.com. For
example foo.example.com and bar.example.com both matches but not foo.bar.example.com. The
name erlang.org matches neither since it is not a CN.
In case where the Presented IDs are fetched from the Subject certificate field, the names may contain wildcard
characters. The function handles this as defined in chapter 6.4.3 in RFC 6125.
There may only be one wildcard character and that is in the first label, for example: *.example.com. This matches
foo.example.com but neither example.com nor foo.bar.example.com.
There may be label characters before or/and after the wildcard. For example: a*d.example.com matches
abcd.example.com and ad.example.com, but not ab.cd.example.com.
In the previous example there is no indication of which protocols are expected. So a client has no indication of whether
it is a web server, an ldap server or maybe a sip server it is connected to. There are fields in the certificate that can
indicate this. To be more exact, the rfc introduces the usage of the X509v3 Subject Alternative Name in
the X509v3 extensions field:
Here kb.example.org serves any protocol while www.example.org presents a secure web server.
The next example has both Subject and Subject Alternate Name present:
The RFC states that if a certificate defines Reference IDs in a Subject Alternate Name field, the Subject field
MUST NOT be used for host name checking, even if it contains valid CN names. Therefore only kb.example.org
and https://www.example.org matches. The match fails both for example.com and foo.example.com
becuase they are in the Subject field which is not checked because the Subject Alternate Name field is
present.
Note:
Other applications like ssl/tls or https might have options that are passed down to the
public_key:pkix_verify_hostname. You will probably not have to call it directly
Suppose our client expects to connect to the web server https://www.example.net. This URI is therefore the Reference
IDs of the client. The call will be:
public_key:pkix_verify_hostname(CertFromHost,
[{uri_id, "https://www.example.net"}
]).
The call will return true or false depending on the check. The caller do not need to handle the matching rules in
the rfc. The matching will proceed as:
• If there is a Subject Alternate Name field, the {uri_id,string()} in the function call will be
compared to any {uniformResourceIdentifier,string()} in the Certificate field. If the two
strings() are equal (case insensitive), there is a match. The same applies for any {dns_id,string()}
in the call which is compared with all {dNSName,string()} in the Certificate field.
• If there is NO Subject Alternate Name field, the Subject field will be checked. All CN names will be
compared to all hostnames extracted from {uri_id,string()} and from {dns_id,string()}.
...
Extract = fun({uri_id, "myspecial://"++HostName}) -> HostName;
(_Else) -> default
end,
...
public_key:pkix_verify_hostname(CertFromHost, RefIDs,
[{fqdn_fun, Extract}])
...
...
Match = fun({uri_id,"myspecial://"++A},
{uniformResourceIdentifier,"myspecial://"++B}) ->
my_match(A,B);
(_RefID, _PresentedID) ->
default
end,
...
public_key:pkix_verify_hostname(CertFromHost, RefIDs,
[{match_fun, Match}]),
...
In case of a match operation between a ReferenceID and a CN value from the Subject field, the first argument to
the fun is the extracted hostname from the ReferenceID, and the second argument is the tuple {cn, string()}
taken from the Subject field. That makes it possible to have separate matching rules for Presented IDs from the
Subject field and from the Subject Alternate Name field.
The default matching transformes the ascii values in strings to lowercase before comparing. The match_fun is
however called without any transfomation applied to the strings. The reason is to enable the user to do unforseen
handling of the strings where the original format is needed.
"Pinning" a Certificate
The RFC 6125 defines pinning as:
"The act of establishing a cached name association between the application service's certificate and one of the client's
reference identifiers, despite the fact that none of the presented identifiers matches the given reference identifier. ..."
The purpose is to have a mechanism for a human to accept an otherwise faulty Certificate. In for example a web
browser, you could get a question like
Warning: you wanted to visit the site www.example.com, but the certificate is for shop.example.com. Accept anyway
(yes/no)?"
This could be accomplished with the option fail_callback which will be called if the hostname verification fails:
Returns a list of public keys and their related attributes. Each pair of key and attribute corresponds to one entry in
the known hosts file:
Returns a list of public keys and their related attributes. Each pair of key and attribute corresponds to one entry in
the authorized key file:
public_key
Application
Provides encode/decode of different file formats (PEM, OpenSSH), digital signature and verification functions,
validation of certificate paths and certificate revocation lists (CRLs) and other functions for handling of certificates,
keys and CRLs.
• Supports RFC 5280 - Internet X.509 Public-Key Infrastructure Certificate and Certificate Revocation List
(CRL) Profile. Certificate policies are currently not supported.
• Supports PKCS-1 - RSA Cryptography Standard
• Supports DSS - Digital Signature Standard (DSA - Digital Signature Algorithm)
• Supports PKCS-3 - Diffie-Hellman Key Agreement Standard
• Supports PKCS-5 - Password-Based Cryptography Standard
• Supports AES - Use of the Advanced Encryption Standard (AES) Algorithm in Cryptographic Message
Syntax (CMS)
• Supports PKCS-8 - Private-Key Information Syntax Standard
• Supports PKCS-10 - Certification Request Syntax Standard
DEPENDENCIES
The public_key application uses the Crypto application to perform cryptographic operations and the ASN-1
application to handle PKIX-ASN-1 specifications, hence these applications must be loaded for the public_key
application to work. In an embedded environment this means they must be started with application:start/
[1,2] before the public_key application is started.
SEE ALSO
application(3)
public_key
Erlang module
Use the following include directive to get access to the records and constant macros described here and in the User's
Guide:
-include_lib("public_key/include/public_key.hrl").
Data Types
oid() = tuple()
Object identifier, a tuple of integers as generated by the ASN.1 compiler.
der_encoded() = binary()
pki_asn1_type() =
'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey' |
'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' |
'SubjectPublicKeyInfo' | 'PrivateKeyInfo' |
'CertificationRequest' | 'CertificateList' | 'ECPrivateKey' |
'EcpkParameters'
asn1_type() = atom()
ASN.1 type present in the Public Key applications ASN.1 specifications.
pem_entry() =
{pki_asn1_type(),
der_or_encrypted_der(),
not_encrypted | cipher_info()}
der_or_encrypted_der() = binary()
cipher_info() = {cipher(), cipher_info_params()}
cipher() = string()
salt() = binary()
cipher_info_params() =
salt() |
{#'PBEParameter'{}, digest_type()} |
#'PBES2-params'{}
Cipher = "RC2-CBC" | "DES-CBC" | "DES-EDE3-CBC"
rsa_public_key() |
rsa_pss_public_key() |
dsa_public_key() |
ec_public_key() |
ed_public_key()
rsa_public_key() = #'RSAPublicKey'{}
rsa_pss_public_key() =
{#'RSAPublicKey'{}, #'RSASSA-PSS-params'{}}
dsa_public_key() = {integer(), #'Dss-Parms'{}}
ec_public_key() = {#'ECPoint'{}, ecpk_parameters_api()}
ecpk_parameters() =
{ecParameters, #'ECParameters'{}} |
{namedCurve, Oid :: tuple()}
ecpk_parameters_api() =
ecpk_parameters() |
#'ECParameters'{} |
{namedCurve, Name :: crypto:ec_named_curve()}
ed_public_key() =
{#'ECPoint'{}, ed_params()} |
{ed_pub, ed25519 | ed448, Key :: binary()}
Warning:
The tagged ed_pub format will not be returned from any public_key functions but can be used as input, should
be considered deprecated.
Warning:
The tagged ed_pri format will not be returned from any public_key functions but can be used as input, should be
considered deprecated.
key_params() =
#'DHParameter'{} |
{namedCurve, oid()} |
#'ECParameters'{} |
{rsa, Size :: integer(), PubExp :: integer()}
digest_type() =
none | sha1 |
crypto:rsa_digest_type() |
crypto:dss_digest_type() |
crypto:ecdsa_digest_type()
crl_reason() =
unspecified | keyCompromise | cACompromise |
affiliationChanged | superseded | cessationOfOperation |
certificateHold | privilegeWithdrawn | aACompromise
cert_id() = {SerialNr :: integer(), issuer_name()}
issuer_name() = {rdnSequence, [[#'AttributeTypeAndValue'{}]]}
ssh_file() =
openssh_public_key | rfc4716_public_key | known_hosts |
auth_keys
Exports
$> cd $ERL_TOP/lib/public_key/priv/
$> generate
---- wait until all background jobs has finished. It may take several days !
$> cat moduli-* > moduli
$> cd ..; make
Cert =
der_encoded() | #'OTPCertificate'{} | #'CertificateList'{}
IssuerCert = der_encoded() | #'OTPCertificate'{}
Checks if IssuerCert issued Cert.
fun(OtpCert :: #'OTPCertificate'{},
Event :: {bad_cert, Reason :: atom() | {revoked, atom()}} |
{extension, #'Extension'{}},
InitialUserState :: term()) ->
{valid, UserState :: term()} |
{valid_peer, UserState :: term()} |
{fail, Reason :: term()} |
{unknown, UserState :: term()}.
If the verify callback fun returns {fail, Reason}, the verification process is immediately stopped. If
the verify callback fun returns {valid, UserState}, the verification process is continued. This can be
used to accept specific path validation errors, such as selfsigned_peer, as well as verifying application-
specific extensions. If called with an extension unknown to the user application, the return value {unknown,
UserState} is to be used.
Warning:
Note that user defined custom verify_fun may alter original path validation error (e.g
selfsigned_peer). Use with caution.
{max_path_length, integer()}
The max_path_length is the maximum number of non-self-issued intermediate certificates that can follow
the peer certificate in a valid certification path. So, if max_path_length is 0, the PEER must be signed
by the trusted ROOT-CA directly, if it is 1, the path can be PEER, CA, ROOT-CA, if it is 2, the path can be
PEER, CA, CA, ROOT-CA, and so on.
Possible reasons for a bad certificate:
cert_expired
Certificate is no longer valid as its expiration date has passed.
invalid_issuer
Certificate issuer name does not match the name of the issuer certificate in the chain.
invalid_signature
Certificate was not signed by its issuer certificate in the chain.
name_not_permitted
Invalid Subject Alternative Name extension.
missing_basic_constraint
Certificate, required to have the basic constraints extension, does not have a basic constraints extension.
invalid_key_usage
Certificate key is used in an invalid way according to the key-usage extension.
{revoked, crl_reason()}
Certificate has been revoked.
atom()
Application-specific error reason that is to be checked by the verify_fun.
The fun uses the information in the distribution point to access the latest possible version of the CRL. If this fun
is not specified, Public Key uses the default implementation:
{issuer_fun, fun()}
The fun has the following type specification:
fun(#'DistributionPoint'{}, #'CertificateList'{},
{rdnSequence,[#'AttributeTypeAndValue'{}]}, term()) ->
{ok, #'OTPCertificate'{}, [der_encoded]}
The fun returns the root certificate and certificate chain that has signed the CRL.
{undetermined_details, boolean()}
Defaults to false. When revocation status cannot be determined, and this option is set to true, details of why no
CRLs where accepted are included in the return value.
[#'Extension'{extnID = ?'id-ce-keyUsage',
extnValue = [keyCertSign, cRLSign],
critical = false},
#'Extension'{extnID = ?'id-ce-basicConstraints',
extnValue = #'BasicConstraints'{cA = true},
critical = true}]
Default extensions included in the server peer cert if not otherwise specified are:
[#'Extension'{extnID = ?'id-ce-keyUsage',
extnValue = [digitalSignature, keyAgreement],
critical = false},
#'Extension'{extnID = ?'id-ce-subjectAltName',
extnValue = [{dNSName, Hostname}],
critical = false}]
Hostname is the result of calling net_adm:localhost() in the Erlang node where this funcion is called.
Note:
Note that the generated certificates and keys does not provide a formally correct PKIX-trust-chain and they cannot
be used to achieve real security. This function is provided for testing purposes only.
pkix_subject_id(Cert) -> ID
Types:
Cert = der_encoded() | #'OTPCertificate'{}
ID = cert_id()
Returns the X509 certificate subject id.
See pkix_verify_hostname_match_fun/1 for a function that takes a protocol name as argument and returns a
fun/2 suitable for this option and Re-defining the match operation in the User's Guide for an example.
fail_callback
If a matching fails, there could be circumstances when the certificate should be accepted anyway. Think
for example of a web browser where you choose to accept an outdated certificate. This option enables
implementation of such a function. This fun/1 is called when no ReferenceID matches. The return value
of the fun (a boolean()) decides the outcome. If true the the certificate is accepted otherwise it is rejected.
See "Pinning" a Certificate in the User's Guide.
fqdn_fun
This option augments the host name extraction from URIs and other Reference IDs. It could for example be a
very special URI that is not standardised. The fun takes a Reference ID as argument and returns one of:
• the hostname
• the atom default: the default host name extract function will be used
• the atom undefined: a host name could not be extracted. The pkix_verify_hostname/3 will return
false.
For an example, see Hostname extraction in the User's Guide.
SshBin = binary()
Type = ssh2_pubkey | OtherType | InternalType
OtherType = public_key | ssh_file()
InternalType = new_openssh
Decoded = Decoded_ssh2_pubkey | Decoded_OtherType
Decoded_ssh2_pubkey = public_key()
Decoded_OtherType = [{public_key(), Attributes}]
Attributes = [{atom(), term()}]
Note:
This function is deprecated and should not be used in new programs. Use ssh_file:decode/2 instead.
Decodes an SSH file-binary. In the case of known_hosts or auth_keys, the binary can include one or more
lines of the file. Returns a list of public keys and their attributes, possible attribute values depends on the file type
represented by the binary.
If the Type is ssh2_pubkey, the result will be Decoded_ssh2_pubkey. Otherwise it will be
Decoded_OtherType.
RFC4716 attributes - see RFC 4716.
{headers, [{string(), utf8_string()}]}
auth_key attributes - see manual page for sshd.
{comment, string()}
{options, [string()]}
{bits, integer()} - In SSH version 1 files.
known_host attributes - see manual page for sshd.
{hostnames, [string()]}
{comment, string()}
{bits, integer()} - In SSH version 1 files.
Example: {ok, SshBin} = file:read_file("known_hosts").
If Type is public_key the binary can be either an RFC4716 public key or an OpenSSH public key.
Note:
This function is deprecated and should not be used in new programs. Use ssh_file:encode/2 instead.
Encodes a list of SSH file entries (public keys and attributes) to a binary. Possible attributes depend on the file type,
see ssh_decode/2 .
If the Type is ssh2_pubkey, the InData shall be InData_ssh2_pubkey. Otherwise it shall be
OtherInData.
Note:
This function is deprecated and should not be used in new programs. Use ssh:hostkey_fingerprint/1 or
ssh:hostkey_fingerprint/2 instead.
The algorithm in ssh_hostkey_fingerprint/1 is md5 to be compatible with older ssh-keygen commands. The
string from the second variant is prepended by the algorithm name in uppercase as in newer ssh-keygen commands.
Examples:
2> public_key:ssh_hostkey_fingerprint(Key).
"f5:64:a6:c1:5a:cb:9f:0a:10:46:a2:5c:3e:2f:57:84"
3> public_key:ssh_hostkey_fingerprint(md5,Key).
"MD5:f5:64:a6:c1:5a:cb:9f:0a:10:46:a2:5c:3e:2f:57:84"
4> public_key:ssh_hostkey_fingerprint(sha,Key).
"SHA1:bSLY/C4QXLDL/Iwmhyg0PGW9UbY"
5> public_key:ssh_hostkey_fingerprint(sha256,Key).
"SHA256:aZGXhabfbf4oxglxltItWeHU7ub3Dc31NcNw2cMJePQ"
6> public_key:ssh_hostkey_fingerprint([sha,sha256],Key).
["SHA1:bSLY/C4QXLDL/Iwmhyg0PGW9UbY",
"SHA256:aZGXhabfbf4oxglxltItWeHU7ub3Dc31NcNw2cMJePQ"]