.TH public_key 3erl "public_key 0.22.1" "Ericsson AB" "Erlang Module Definition" .SH NAME public_key \- API module for public key infrastructure. .SH DESCRIPTION .LP This module provides functions to handle public key infrastructure\&. It can encode/decode different file formats (PEM, openssh), sign and verify digital signatures and validate certificate paths and certificate revocation lists\&. .SH "PUBLIC_KEY" .RS 2 .TP 2 * public_key requires the crypto and asn1 applications, the latter since R16 (hopefully the runtime dependency on asn1 will be removed again in the future)\&. .LP .TP 2 * Supports RFC 5280 - Internet X\&.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile .LP .TP 2 * Supports PKCS-1 - RSA Cryptography Standard .LP .TP 2 * Supports DSS- Digital Signature Standard (DSA - Digital Signature Algorithm) .LP .TP 2 * Supports PKCS-3 - Diffie-Hellman Key Agreement Standard .LP .TP 2 * Supports PKCS-5 - Password-Based Cryptography Standard .LP .TP 2 * Supports PKCS-8 - Private-Key Information Syntax Standard .LP .TP 2 * Supports PKCS-10 - Certification Request Syntax Standard .LP .RE .SH "COMMON DATA TYPES " .LP .RS -4 .B Note: .RE All records used in this manual are generated from ASN\&.1 specifications and are documented in the User\&'s Guide\&. See \fBPublic key records\fR\& and \fBX\&.509 Certificate records\fR\&\&. .LP Use the following include directive to get access to the records and constant macros described here and in the User\&'s Guide\&. .LP .nf -include_lib("public_key/include/public_key.hrl"). .fi .LP \fIData Types \fR\& .LP .LP .nf oid() - Object Identifier, a tuple of integers as generated by the ASN1 compiler. .fi .LP .LP .nf boolean() = true | false .fi .LP .LP .nf string() = [bytes()] .fi .LP .LP .nf der_encoded() = binary() .fi .LP .LP .nf pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey' | 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo' | 'PrivateKeyInfo' | 'CertificationRequest' | 'ECPrivateKey' | 'EcpkParameters' .fi .LP .LP .nf pem_entry () = {pki_asn1_type(), binary(), %% DER or encrypted DER not_encrypted | cipher_info()} .fi .LP .LP .nf cipher_info() = {"RC2-CBC | "DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8) | {#'PBEParameter{}, digest_type()} |#'PBES2-params'{}} .fi .LP .LP .nf public_key() = rsa_public_key() | dsa_public_key() | ec_public_key() .fi .LP .LP .nf private_key() = rsa_private_key() | dsa_private_key() | ec_private_key() .fi .LP .LP .nf rsa_public_key() = #'RSAPublicKey'{} .fi .LP .LP .nf rsa_private_key() = #'RSAPrivateKey'{} .fi .LP .LP .nf dsa_public_key() = {integer(), #'Dss-Parms'{}} .fi .LP .LP .nf dsa_private_key() = #'DSAPrivateKey'{} .fi .LP .LP .nf ec_public_key() = {#'ECPoint'{}, #'EcpkParameters'{} | {namedCurve, oid()}} .fi .LP .LP .nf ec_private_key() = #'ECPrivateKey'{} .fi .LP .LP .nf public_crypt_options() = [{rsa_pad, rsa_padding()}]. .fi .LP .LP .nf rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding' .fi .LP .LP .nf digest_type() - Union of below digest types .fi .LP .LP .nf rsa_digest_type() = 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512' .fi .LP .LP .nf dss_digest_type() = 'sha' .fi .LP .LP .nf ecdsa_digest_type() = 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512' .fi .LP .LP .nf crl_reason() = unspecified | keyCompromise | cACompromise | affiliationChanged | superseded | cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise .fi .LP .LP .nf ssh_file() = openssh_public_key | rfc4716_public_key | known_hosts | auth_keys .fi .SH EXPORTS .LP .B compute_key(OthersKey, MyKey)-> .br .B compute_key(OthersKey, MyKey, Params)-> .br .RS .LP Types: .RS 3 OthersKey = #\&'ECPoint\&'{} | binary(), MyKey = #\&'ECPrivateKey\&'{} | binary() .br Params = #\&'DHParameter\&'{} .br .RE .RE .RS .LP Compute shared secret .RE .LP .B decrypt_private(CipherText, Key) -> binary() .br .B decrypt_private(CipherText, Key, Options) -> binary() .br .RS .LP Types: .RS 3 CipherText = binary() .br Key = rsa_private_key() .br Options = public_crypt_options() .br .RE .RE .RS .LP Public key decryption using the private key\&. See also \fBcrypto:private_decrypt/4\fR\& .RE .LP .B decrypt_public(CipherText, Key) - > binary() .br .B decrypt_public(CipherText, Key, Options) - > binary() .br .RS .LP Types: .RS 3 CipherText = binary() .br Key = rsa_public_key() .br Options = public_crypt_options() .br .RE .RE .RS .LP Public key decryption using the public key\&. See also \fBcrypto:public_decrypt/4\fR\& .RE .LP .B der_decode(Asn1type, Der) -> term() .br .RS .LP Types: .RS 3 Asn1Type = atom() .br .RS 2 ASN\&.1 type present in the public_key applications asn1 specifications\&. .RE Der = der_encoded() .br .RE .RE .RS .LP Decodes a public key ASN\&.1 DER encoded entity\&. .RE .LP .B der_encode(Asn1Type, Entity) -> der_encoded() .br .RS .LP Types: .RS 3 Asn1Type = atom() .br .RS 2 Asn1 type present in the public_key applications ASN\&.1 specifications\&. .RE Entity = term() .br .RS 2 The erlang representation of \fIAsn1Type\fR\& .RE .RE .RE .RS .LP Encodes a public key entity with ASN\&.1 DER encoding\&. .RE .LP .B generate_key(Params) -> {Public::binary(), Private::binary()} | #\&'ECPrivateKey\&'{} .br .RS .LP Types: .RS 3 Params = #\&'DHParameter\&'{} | {namedCurve, oid()} | #\&'ECParameters\&'{} .br .RE .RE .RS .LP Generates a new keypair .RE .LP .B pem_decode(PemBin) -> [pem_entry()] .br .RS .LP Types: .RS 3 PemBin = binary() .br .RS 2 Example {ok, PemBin} = file:read_file("cert\&.pem")\&. .RE .RE .RE .RS .LP Decode PEM binary data and return entries as ASN\&.1 DER encoded entities\&. .RE .LP .B pem_encode(PemEntries) -> binary() .br .RS .LP Types: .RS 3 PemEntries = [pem_entry()] .br .RE .RE .RS .LP Creates a PEM binary .RE .LP .B pem_entry_decode(PemEntry) -> term() .br .B pem_entry_decode(PemEntry, Password) -> term() .br .RS .LP Types: .RS 3 PemEntry = pem_entry() .br Password = string() .br .RE .RE .RS .LP Decodes a PEM entry\&. pem_decode/1 returns a list of PEM entries\&. Note that if the PEM entry is of type \&'SubjectPublickeyInfo\&' it will be further decoded to an rsa_public_key() or dsa_public_key()\&. .RE .LP .B pem_entry_encode(Asn1Type, Entity) -> pem_entry() .br .B pem_entry_encode(Asn1Type, Entity, {CipherInfo, Password}) -> pem_entry() .br .RS .LP Types: .RS 3 Asn1Type = pki_asn1_type() .br Entity = term() .br .RS 2 The Erlang representation of \fIAsn1Type\fR\&\&. If \fIAsn1Type\fR\& is \&'SubjectPublicKeyInfo\&' then \fIEntity\fR\& must be either an rsa_public_key() or a dsa_public_key() and this function will create the appropriate \&'SubjectPublicKeyInfo\&' entry\&. .RE CipherInfo = cipher_info() .br Password = string() .br .RE .RE .RS .LP Creates a PEM entry that can be feed to pem_encode/1\&. .RE .LP .B encrypt_private(PlainText, Key) -> binary() .br .RS .LP Types: .RS 3 PlainText = binary() .br Key = rsa_private_key() .br .RE .RE .RS .LP Public key encryption using the private key\&. See also \fBcrypto:private_encrypt/4\fR\& .RE .LP .B encrypt_public(PlainText, Key) -> binary() .br .RS .LP Types: .RS 3 PlainText = binary() .br Key = rsa_public_key() .br .RE .RE .RS .LP Public key encryption using the public key\&. See also \fBcrypto:public_encrypt/4\fR\& .RE .LP .B pkix_decode_cert(Cert, otp|plain) -> #\&'Certificate\&'{} | #\&'OTPCertificate\&'{} .br .RS .LP Types: .RS 3 Cert = der_encoded() .br .RE .RE .RS .LP Decodes an ASN\&.1 DER encoded PKIX certificate\&. The otp option will use the customized ASN\&.1 specification OTP-PKIX\&.asn1 for decoding and also recursively decode most of the standard parts\&. .RE .LP .B pkix_encode(Asn1Type, Entity, otp | plain) -> der_encoded() .br .RS .LP Types: .RS 3 Asn1Type = atom() .br .RS 2 The ASN\&.1 type can be \&'Certificate\&', \&'OTPCertificate\&' or a subtype of either \&. .RE Entity = #\&'Certificate\&'{} | #\&'OTPCertificate\&'{} | a valid subtype .br .RE .RE .RS .LP DER encodes a PKIX x509 certificate or part of such a certificate\&. This function must be used for encoding certificates or parts of certificates that are decoded/created in the otp format, whereas for the plain format this function will directly call der_encode/2\&. .RE .LP .B pkix_is_issuer(Cert, IssuerCert) -> boolean() .br .RS .LP Types: .RS 3 Cert = der_encode() | #\&'OTPCertificate\&'{} .br IssuerCert = der_encode() | #\&'OTPCertificate\&'{} .br .RE .RE .RS .LP Checks if \fIIssuerCert\fR\& issued \fICert\fR\& .RE .LP .B pkix_is_fixed_dh_cert(Cert) -> boolean() .br .RS .LP Types: .RS 3 Cert = der_encode() | #\&'OTPCertificate\&'{} .br .RE .RE .RS .LP Checks if a Certificate is a fixed Diffie-Hellman Cert\&. .RE .LP .B pkix_is_self_signed(Cert) -> boolean() .br .RS .LP Types: .RS 3 Cert = der_encode() | #\&'OTPCertificate\&'{} .br .RE .RE .RS .LP Checks if a Certificate is self signed\&. .RE .LP .B pkix_issuer_id(Cert, IssuedBy) -> {ok, IssuerID} | {error, Reason} .br .RS .LP Types: .RS 3 Cert = der_encode() | #\&'OTPCertificate\&'{} .br IssuedBy = self | other .br IssuerID = {integer(), {rdnSequence, [#\&'AttributeTypeAndValue\&'{}]}} .br .RS 2 The issuer id consists of the serial number and the issuers name\&. .RE Reason = term() .br .RE .RE .RS .LP Returns the issuer id\&. .RE .LP .B pkix_normalize_name(Issuer) -> Normalized .br .RS .LP Types: .RS 3 Issuer = {rdnSequence,[#\&'AttributeTypeAndValue\&'{}]} .br Normalized = {rdnSequence, [#\&'AttributeTypeAndValue\&'{}]} .br .RE .RE .RS .LP Normalizes a issuer name so that it can be easily compared to another issuer name\&. .RE .LP .B pkix_path_validation(TrustedCert, CertChain, Options) -> {ok, {PublicKeyInfo, PolicyTree}} | {error, {bad_cert, Reason}} .br .RS .LP Types: .RS 3 TrustedCert = #\&'OTPCertificate\&'{} | der_encode() | atom() .br .RS 2 Normally a trusted certificate but it can also be a path validation error that can be discovered while constructing the input to this function and that should be run through the \fIverify_fun\fR\&\&. For example \fIunknown_ca \fR\& or \fIselfsigned_peer \fR\& .RE CertChain = [der_encode()] .br .RS 2 A list of DER encoded certificates in trust order ending with the peer certificate\&. .RE Options = proplists:proplist() .br PublicKeyInfo = {?\&'rsaEncryption\&' | ?\&'id-dsa\&', rsa_public_key() | integer(), \&'NULL\&' | \&'Dss-Parms\&'{}} .br PolicyTree = term() .br .RS 2 At the moment this will always be an empty list as Policies are not currently supported .RE Reason = cert_expired | invalid_issuer | invalid_signature | name_not_permitted | missing_basic_constraint | invalid_key_usage | {revoked, crl_reason()} | atom() .br .RE .RE .RS .LP Performs a basic path validation according to RFC 5280\&. However CRL validation is done separately by \fBpkix_crls_validate/3 \fR\& and should be called from the supplied \fIverify_fun\fR\& .RS 2 .TP 2 .B {verify_fun, fun()}: The fun should be defined as: .LP .nf 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()}. .fi .RS 2 .LP 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 \fIselfsigned_peer\fR\& as well as verifying application specific extensions\&. If called with an extension unknown to the user application the return value {unknown, UserState} should be used\&. .RE .TP 2 .B {max_path_length, integer()}: The \fImax_path_length\fR\& is the maximum number of non-self-issued intermediate certificates that may follow the peer certificate in a valid certification path\&. So if \fImax_path_length\fR\& is 0 the PEER must be signed by the trusted ROOT-CA directly, if 1 the path can be PEER, CA, ROOT-CA, if it is 2 PEER, CA, CA, ROOT-CA and so on\&. .RE .LP Possible reasons for a bad certificate are: .RS 2 .TP 2 .B cert_expired: The certificate is no longer valid as its expiration date has passed\&. .TP 2 .B invalid_issuer: The certificate issuer name does not match the name of the issuer certificate in the chain\&. .TP 2 .B invalid_signature: The certificate was not signed by its issuer certificate in the chain\&. .TP 2 .B name_not_permitted: Invalid Subject Alternative Name extension\&. .TP 2 .B missing_basic_constraint: Certificate, required to have the basic constraints extension, does not have a basic constraints extension\&. .TP 2 .B invalid_key_usage: Certificate key is used in an invalid way according to the key usage extension\&. .TP 2 .B {revoked, crl_reason()}: Certificate has been revoked\&. .TP 2 .B atom(): Application specific error reason that should be checked by the verify_fun .RE .RE .LP .B pkix_crls_validate(OTPCertificate, DPAndCRLs, Options) -> CRLStatus() .br .RS .LP Types: .RS 3 OTPCertificate = #\&'OTPCertificate\&'{} .br DPAndCRLs = [{DP::#\&'DistributionPoint\&'{}, {DerCRL::der_encoded(), CRL::#\&'CertificateList\&'{}}}] .br Options = proplists:proplist() .br CRLStatus() = valid | {bad_cert, revocation_status_undetermined} | {bad_cert, {revoked, crl_reason()}} .br .RE .RE .RS .LP Performs CRL validation\&. It is intended to be called from the verify fun of \fB pkix_path_validation/3 \fR\& .RS 2 .TP 2 .B {update_crl, fun()}: The fun has the following type spec: .LP .nf fun(#'DistributionPoint'{}, #'CertificateList'{}) -> #'CertificateList'{} .fi .RS 2 .LP The fun should use the information in the distribution point to acesses the lates possible version of the CRL\&. If this fun is not specified public_key will use the default implementation: .RE .LP .nf fun(_DP, CRL) -> CRL end .fi .TP 2 .B {issuer_fun, fun()}: The fun has the following type spec: .LP .nf fun(#'DistributionPoint'{}, #'CertificateList'{}, {rdnSequence,[#'AttributeTypeAndValue'{}]}, term()) -> {ok, #'OTPCertificate'{}, [der_encoded]} .fi .RS 2 .LP The fun should return the root certificate and certificate chain that has signed the CRL\&. .RE .LP .nf fun(DP, CRL, Issuer, UserState) -> {ok, RootCert, CertChain} .fi .RE .RE .LP .B pkix_sign(#\&'OTPTBSCertificate\&'{}, Key) -> der_encode() .br .RS .LP Types: .RS 3 Key = rsa_public_key() | dsa_public_key() .br .RE .RE .RS .LP Signs a \&'OTPTBSCertificate\&'\&. Returns the corresponding der encoded certificate\&. .RE .LP .B pkix_sign_types(AlgorithmId) -> {DigestType, SignatureType} .br .RS .LP Types: .RS 3 AlgorithmId = oid() .br .RS 2 Signature oid from a certificate or a certificate revocation list .RE DigestType = rsa_digest_type() | dss_digest_type() .br SignatureType = rsa | dsa .br .RE .RE .RS .LP Translates signature algorithm oid to erlang digest and signature types\&. .RE .LP .B pkix_verify(Cert, Key) -> boolean() .br .RS .LP Types: .RS 3 Cert = der_encode() .br Key = rsa_public_key() | dsa_public_key() .br .RE .RE .RS .LP Verify PKIX x\&.509 certificate signature\&. .RE .LP .B sign(Msg, DigestType, Key) -> binary() .br .RS .LP Types: .RS 3 Msg = binary() | {digest,binary()} .br .RS 2 The msg is either the binary "plain text" data to be signed or it is the hashed value of "plain text" i\&.e\&. the digest\&. .RE DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type() .br Key = rsa_private_key() | dsa_private_key() | ec_private_key() .br .RE .RE .RS .LP Creates a digital signature\&. .RE .LP .B ssh_decode(SshBin, Type) -> [{public_key(), Attributes::list()}] .br .RS .LP Types: .RS 3 SshBin = binary() .br .RS 2 Example {ok, SshBin} = file:read_file("known_hosts")\&. .RE Type = public_key | ssh_file() .br .RS 2 If \fIType\fR\& is \fIpublic_key\fR\& the binary may be either a rfc4716 public key or a openssh public key\&. .RE .RE .RE .RS .LP Decodes a ssh file-binary\&. In the case of know_hosts or auth_keys the binary may 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\&. .RS 2 .TP 2 .B rfc4716 attributes - see RFC 4716: {headers, [{string(), utf8_string()}]} .TP 2 .B auth_key attributes - see man sshd : {comment, string()}{options, [string()]}{bits, integer()} - In ssh version 1 files .TP 2 .B known_host attributes - see man sshd: {hostnames, [string()]}{comment, string()}{bits, integer()} - In ssh version 1 files .RE .RE .LP .B ssh_encode([{Key, Attributes}], Type) -> binary() .br .RS .LP Types: .RS 3 Key = public_key() .br Attributes = list() .br Type = ssh_file() .br .RE .RE .RS .LP Encodes a list of ssh file entries (public keys and attributes) to a binary\&. Possible attributes depends on the file type, see \fB ssh_decode/2 \fR\& .RE .LP .B verify(Msg, DigestType, Signature, Key) -> boolean() .br .RS .LP Types: .RS 3 Msg = binary() | {digest,binary()} .br .RS 2 The msg is either the binary "plain text" data or it is the hashed value of "plain text" i\&.e\&. the digest\&. .RE DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type() .br Signature = binary() .br Key = rsa_public_key() | dsa_public_key() | ec_public_key() .br .RE .RE .RS .LP Verifies a digital signature .RE