public_key

v1.19-rc0

Public_Key Application

The Public Key application deals with public-key related file formats, digital signatures, and X-509 certificates. It handles validation of certificate paths and certificate revocation lists (CRLs) and other functions for handling of certificates, keys and CRLs. It is a library application that does not read or write files, it expects or returns file contents or partial file contents as binaries. Except for the functions public-key:cacerts_load/0, public-key:cacerts_load/1, and public-key:cacerts_get/0 that reads files.

Supported PKIX functionality

Supports RFC 5280 - Internet X.509 Public-Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile. Certificate policies supported since OTP-26.2

Supports PKCS-1 - RSA Cryptography Standard

Supports DSS - Digital Signature Standard (DSA - Digital Signature Algorithm)

Supports PKCS-3 - Diffie-Hellman Key Agreement Standard

Supports Cryptographic Message Syntax (CMS) (http://www.ietf.org/rfc/rfc5652.txt) including Password-Based Encryption with original PKCS-5 support, but currently excluding offical support for most of section 10-12 (if proven useful, especially Attribute Certificates v2, it might be added later).

Supports PKCS-8 - Private-Key Information Syntax Standard

Supports PKCS-10 - Certification Request Syntax Standard

Supports PKIXCMP - Certificate Management Protocol

Supports PKIXCRMF - Certificate Request Message Format

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.

Error Logger and Event Handlers

The public_key application is a library application and does not use the error logger. The functions will either succeed or fail with a runtime error.

See Also

application

Public_Key Release Notes

Public_Key 1.19

Improvements and New Features

Added support for the Public-Key Infrastructure Certificate Management Protocol (PKICMP) ASN.1 specification.

Own Id: OTP-19861 Aux Id: PR-10386

Public_Key 1.18.3

Fixed Bugs and Malfunctions

NIFs and linked-in drivers are now loadable when running in an Erlang source tree on Windows.

Own Id: OTP-19686 Aux Id: PR-9969

Added missing reference to SignedAttributes so that it now works with the der_encode and der_decode functions.

Own Id: OTP-19727 Aux Id: PR-10091

Improvements and New Features

Added support for quantum crypto signature algorithm ML-DSA (ssl and public_key) and key exchange algorithm ML-KEM (ssl).

Own Id: OTP-19552 Aux Id: PR-10004

Public_Key 1.18.2

Fixed Bugs and Malfunctions

Adjustments in include file to retain compatibility with supported ASN-1 standards, although not all record and macros are explicitly documented.

Own Id: OTP-19678 Aux Id: PR-10008, PR-9955, GH-10001

Handle certificates that are signed with RSASSA-PSS but the PSS params are specified in the 'SignatureAlgorithm' of the signed cert and not in the signer's 'SubjectPublicKeyInfo'.

Own Id: OTP-19699 Aux Id: GH-9632, PR-10023

Add modern ASN-1 specs to be able to retain support for ExtensionRequest from legacy PKCS-9 spec.

Own Id: OTP-19703 Aux Id: GH-10028, PR-10031

Public_Key 1.18.1

Fixed Bugs and Malfunctions

Add back some ASN-1 macros and definitions that should be included in API.

Own Id: OTP-19644 Aux Id: PR-9880

Public_Key 1.18

Fixed Bugs and Malfunctions

Enable public_key to decode legacy certs using md2 hash.

Own Id: OTP-19616 Aux Id: PR-9755, GH-9754

Improvements and New Features

When compiling C/C++ code on Unix systems, the compiler hardening flags suggested by the Open Source Security Foundation are now enabled by default. To disable them, pass --disable-security-hardening-flags to configure.

Own Id: OTP-19519 Aux Id: PR-9441

Ignore instead of crashing unhandled entries when loading CA-certificates.

Own Id: OTP-19573 Aux Id: GH-9565, PR-9677

The license and copyright header has changed format to include an SPDX-License-Identifier. At the same time, most files have been updated to follow a uniform standard for license headers.

Own Id: OTP-19575 Aux Id: PR-9670

The ancient ASN.1 modules used in public_key has been replaced with more modern versions, but we have strived to keep the documented Erlang API for the public_key application compatible.

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19612 Aux Id: PR-9774

Public_Key 1.17.1.1

Fixed Bugs and Malfunctions

Handle certificates that are signed with RSASSA-PSS but the PSS params are specified in the 'SignatureAlgorithm' of the signed cert and not in the signer's 'SubjectPublicKeyInfo'.

Own Id: OTP-19699 Aux Id: GH-9632, PR-10023

Public_Key 1.17.1

Fixed Bugs and Malfunctions

Consider keyCertSign to compatible with extended key usage for TLS client/server auth in CAs, adhere to wide spread implementations

Own Id: OTP-19240 Aux Id: PR-9286, GH-9208

Public_Key 1.17

Improvements and New Features

public_key:cacerts_load/1 can now be configured via the application environment.

Own Id: OTP-19321 Aux Id: PR-8920

On MacOS, CA certificates are now also loaded from the system keychain.

Own Id: OTP-19375 Aux Id: PR-8844

Public_Key 1.16.4

Fixed Bugs and Malfunctions

If both ext-key-usage and key-usage are defined for a certificate it should be checked that these usages are consistent with each other. This will have the affect that such certificates where the ext-key-usages is marked as critical and the usages is consistent with the key-use it can be considered valid without mandatory application specific checks for the ext-key-useage extension.

Own Id: OTP-19240 Aux Id: PR-8840, OTP-19532

Handle decoding of EDDSA key properly, when decoding a PEM file that contains only the public EDDSA key.

Own Id: OTP-19350 Aux Id: GH-9009, PR-9053

Public_Key 1.16.3

Fixed Bugs and Malfunctions

Introduction of verify_fun/4 unfortunately introduced an argument switch for some specific path validation errors so that verify_fun/3 could under these circumstances be called with a DER cert instead of a decod cert, also in this situation the verify_fun/4 would have the certificates in reverse order.

Own Id: OTP-19245 Aux Id: Gh-8832

Improvements and New Features

Do not hide crypto badarg reason, this error handling enhancement facilitates debugging. These kind of runtime errors are not documented and should never be relied on for matching, they are intended for catching input errors early.

Own Id: OTP-19238

Public_Key 1.16.2

Fixed Bugs and Malfunctions

For completeness handle rsa_pss implicit default value, although this will probably not be commonly used as it provides very weak security.

Own Id: OTP-19179

The public_key:cacerts_load() function could in some error cases return undefined instead of {error, Reason}.

Own Id: OTP-19183 Aux Id: GH-8604

Added support for DragonFly.

Own Id: OTP-19191 Aux Id: PR-8703

Improvements and New Features

Deprecation of RSA encryption functions has been reverted, as there still exists legitimate use cases with other padding modes than PKCS-1.

While use PCKS-1 padding with some versions of cryptolib could be considered secure, we still recommend using other algorithms that are less sensitive to oracle attacks.

Own Id: OTP-19163

It is now possible to use a verification fun of arity 4, giving the user fun access to both encoded and decoded versions of the certificate. This is desirable as a workaround for encoding errors preventing re-encoding from being reliable. This also saves some work load if the encoded version is needed.

Note that calling public_key:pkix_path_validation/3 with only decoded certs is not recommended, due to the decoding workarounds, although it will work as long as the workarounds are not needed.

If the decoded version is needed before thecall to public_key it is recommend to use the combined_cert- type to avoid double decoding. Note that the path validation algorithm itself always needs both the encoded and decoded versions of the certs.

The ssl implementation will now benefit from using this function instead of emulating the verify_fun/4.

Own Id: OTP-19169

Public_Key 1.16.1

Fixed Bugs and Malfunctions

Fix bug in dnsName constraint check, could cause valid cert to be considered bad during path validation.

Own Id: OTP-19100 Aux Id: GH-8482, PR-8508

Public_Key 1.16

Improvements and New Features

The ssl client can negotiate and handle certificate status request (OCSP stapling support on the client side).

Thanks to voltone for interop testing and related discussions.

Own Id: OTP-18606 Aux Id: OTP-16875,OTP-16448

The exception reason when public_key:cacerts_get/0 failed has been improved.

Own Id: OTP-18609 Aux Id: GH-7295, PR-7302

Key customization support has been extended to allow flexibility for implementers of for instance hardware security modules (HSM) or trusted platform modules (TPM).

Own Id: OTP-18876 Aux Id: PR-7898, PR-7475

The documentation has been migrated to use Markdown and ExDoc.

Own Id: OTP-18955 Aux Id: PR-8026

The existing function ssl:key_exporter_materials/4 is now documented and supported.

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19016 Aux Id: PR-8233

Due to another attack on PKCS #1 v1.5 padding, known as the Marvin attack, about which we were alerted by Hubert Kario from Red Hat. You can find more details about the attack at https://people.redhat.com/~hkario/marvin/ Functions that may be vulnerable are now deprecated.

Note that you might mitigate the problem by using appropriate versions of OpenSSL together with our software, but we recommend not using them at all.

Also avoid using TLS versions prior to TLS-1.2 (not supported by default) and do not enable RSA-key exchange cipher suites (not supported by default).

POTENTIAL INCOMPATIBILITY

Own Id: OTP-19075

Public_Key 1.15.1.6

Fixed Bugs and Malfunctions

Handle certificates that are signed with RSASSA-PSS but the PSS params are specified in the 'SignatureAlgorithm' of the signed cert and not in the signer's 'SubjectPublicKeyInfo'.

Own Id: OTP-19699 Aux Id: GH-9632, PR-10023

Public_Key 1.15.1.5

Fixed Bugs and Malfunctions

Consider keyCertSign to compatible with extended key usage for TLS client/server auth in CAs, adhere to wide spread implementations

Own Id: OTP-19240 Aux Id: PR-9286, GH-9208

Public_Key 1.15.1.4

Fixed Bugs and Malfunctions

If both ext-key-usage and key-usage are defined for a certificate it should be checked that these usages are consistent with each other. This will have the affect that such certificates where the ext-key-usages is marked as critical and the usages is consistent with the key-use it can be considered valid without mandatory application specific checks for the ext-key-useage extension.

Own Id: OTP-19240 Aux Id: PR-8840, OTP-19532

Handle decoding of EDDSA key properly, when decoding a PEM file that contains only the public EDDSA key.

Own Id: OTP-19350 Aux Id: GH-9009, PR-9053

Public_Key 1.15.1.3

Improvements and New Features

Do not hide crypto badarg reason, this error handling enhancement facilitates debugging. These kind of runtime errors are not documented and should never be relied on for matching, they are intended for catching input errors early.

Own Id: OTP-19238 Aux Id: PR-8831

Public_Key 1.15.1.2

Fixed Bugs and Malfunctions

For completeness handle rsa_pss implicit default value, although this will probably not be commonly used as it provides very weak security.

Own Id: OTP-19179

Public_Key 1.15.1.1

Fixed Bugs and Malfunctions

Fix bug in dnsName constraint check, could cause valid cert to be considered bad during path validation.

Own Id: OTP-19100 Aux Id: GH-8482, PR-8508

Public_Key 1.15.1

Fixed Bugs and Malfunctions

Hostname prefix with X number of dots should not be accepted.

Own Id: OTP-18935 Aux Id: GH-8021

Public_Key 1.15

Fixed Bugs and Malfunctions

ssl application will validate id-kp-serverAuth and id-kp-clientAuth extended key usage only in end entity certificates. public_key application will disallow "anyExtendedKeyUsage" for CA certificates that includes the extended key usage extension and marks it critical.

Own Id: OTP-18739

Modernize ECC handling so that crypto FIPS support works as expected.

Own Id: OTP-18854

Improvements and New Features

Support certificate policies in path_validation - as described by RFC 5280.

Own Id: OTP-17844 Aux Id: ERIERL-738

Add more search paths for cacerts on Illumos.

Own Id: OTP-18814 Aux Id: PR-7435

Make it possible to handle invalid date formats in the verify_fun for pkix_path_validation/3

Own Id: OTP-18867 Aux Id: GH-7515

Public_Key 1.14.1

Fixed Bugs and Malfunctions

Country name comparison shall be case insensitive

Own Id: OTP-18718 Aux Id: GH-7546

Add check to disallow duplicate certs in a path

Own Id: OTP-18723 Aux Id: GH-6394

Public_Key 1.14

Improvements and New Features

Handling of on_load modules during boot has been improved by adding an extra step in the boot order for embedded mode that runs all on_load handlers, instead of relying on explicit invocation of them, later, when the kernel supervision tree starts.

This is mostly a code improvement and OTP internal simplification to avoid future bugs and to simplify code maintenance.

Own Id: OTP-18447

Public_Key 1.13.3.6

Fixed Bugs and Malfunctions

Consider keyCertSign to compatible with extended key usage for TLS client/server auth in CAs, adhere to wide spread implementations

Own Id: OTP-19240 Aux Id: PR-9286, GH-9208

Public_Key 1.13.3.5

Fixed Bugs and Malfunctions

If both ext-key-usage and key-usage are defined for a certificate it should be checked that these usages are consistent with each other. This will have the affect that such certificates where the ext-key-usages is marked as critical and the usages is consistent with the key-use it can be considered valid without mandatory application specific checks for the ext-key-useage extension.

Own Id: OTP-19240 Aux Id: PR-8840, OTP-19532

Handle decoding of EDDSA key properly, when decoding a PEM file that contains only the public EDDSA key.

Own Id: OTP-19350 Aux Id: GH-9009, PR-9053

Public_Key 1.13.3.4

Improvements and New Features

Do not hide crypto badarg reason, this error handling enhancement facilitates debugging. These kind of runtime errors are not documented and should never be relied on for matching, they are intended for catching input errors early.

Own Id: OTP-19238 Aux Id: PR-8831

Public_Key 1.13.3.3

Fixed Bugs and Malfunctions

For completeness handle rsa_pss implicit default value, although this will probably not be commonly used as it provides very weak security.

Own Id: OTP-19179

Public_Key 1.13.3.2

Fixed Bugs and Malfunctions

ssl application will validate id-kp-serverAuth and id-kp-clientAuth extended key usage only in end entity certificates. public_key application will disallow "anyExtendedKeyUsage" for CA certificates that includes the extended key usage extension and marks it critical.

Own Id: OTP-18739

Public_Key 1.13.3.1

Fixed Bugs and Malfunctions

Country name comparison shall be case insensitive

Own Id: OTP-18718 Aux Id: GH-7546

Public_Key 1.13.3

Fixed Bugs and Malfunctions

As different solutions of verifying certificate revocation exists move the decode of 'CRLDistributionPoints' so that it will only be decode. When it is actually used in the verification process. This would enable interoperability with systems that use certificates with an invalid empty CRLDistributionPoints extension that they want to ignore and make verification by other means.

Own Id: OTP-18316 Aux Id: GH-6402, PR-6883

public_key:pkix_path_validation validates certificates expiring after 2050

Own Id: OTP-18356 Aux Id: GH-6403

Do not leave exit message in message queue after calling cacerts_load() on MacOS.

Own Id: OTP-18392 Aux Id: GH-6656

Improvements and New Features

Replace size/1 with either tuple_size/1 or byte_size/1

The size/1 BIF is not optimized by the JIT, and its use can result in worse types for Dialyzer.

When one knows that the value being tested must be a tuple, tuple_size/1 should always be preferred.

When one knows that the value being tested must be a binary, byte_size/1 should be preferred. However, byte_size/1 also accepts a bitstring (rounding up size to a whole number of bytes), so one must make sure that the call to byte_size/ is preceded by a call to is_binary/1 to ensure that bitstrings are rejected. Note that the compiler removes redundant calls to is_binary/1, so if one is not sure whether previous code had made sure that the argument is a binary, it does not harm to add an is_binary/1 test immediately before the call to byte_size/1.

Own Id: OTP-18432 Aux Id: GH-6672,PR-6793,PR-6784,PR-6787,PR-6785,PR-6682,PR-6800,PR-6797,PR-6798,PR-6799,PR-6796,PR-6813,PR-6671,PR-6673,PR-6684,PR-6694,GH-6677,PR-6696,PR-6670,PR-6674

Public_Key 1.13.2

Fixed Bugs and Malfunctions

Disregard LDAP URIs when HTTP URIs are expected.

Own Id: OTP-18333 Aux Id: GH-6363

Public_Key 1.13.1

Fixed Bugs and Malfunctions

Support more Linux distributions in cacerts_load/0.

Own Id: OTP-18154 Aux Id: PR-6002

Correct asn1 typenames available in type pki_asn1_type()

Own Id: OTP-18189 Aux Id: ERIERL-829

Sign/verify does now behave as in OTP-24 and earlier for eddsa.

Own Id: OTP-18205 Aux Id: GH-6219

Public_Key 1.13

Improvements and New Features

Added functions to retrieve OS provided CA-certs.

Own Id: OTP-17798 Aux Id: GH-5760

Allow key file passwords to be input as a single binary, that is we change the data type to be the more for the purpose logical data type iodata() instead of string().

Own Id: OTP-17890

The deprecated public_key functions ssh_decode/2, ssh_encode/2, ssh_hostkey_fingerprint/1 and ssh_hostkey_fingerprint/2 are removed.

They are replaced by ssh_file:decode/2, ssh_file:encode/2, ssh:hostkey_fingerprint/1 and ssh:hostkey_fingerprint/2 respectively.

Note that the decode/2 and encode/2 are not exact replacement functions, some minor changes may be needed. Se the manual for more information.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-17921

Public_Key 1.12.0.2

Fixed Bugs and Malfunctions

Country name comparison shall be case insensitive

Own Id: OTP-18718 Aux Id: GH-7546

Public_Key 1.12.0.1

Fixed Bugs and Malfunctions

Correct asn1 typenames available in type pki_asn1_type()

Own Id: OTP-18189 Aux Id: ERIERL-829

Public_Key 1.12

Improvements and New Features

Support password fun for protected keyfiles in ssl:connect function.

Own Id: OTP-17816 Aux Id: PR-5607

Public_Key 1.11.3

Fixed Bugs and Malfunctions

Avoid re-encoding of decoded certificates. This could cause unexpected failures as some subtle encoding errors can be tolerated when decoding but hence creating another sequence of bytes if the decoded value is re-encoded.

Own Id: OTP-17657

Public_Key 1.11.2

Fixed Bugs and Malfunctions

public_key:pkix_sign/2 now honors the salt length from the provided input parameters. Earlier this could result in incorrect signatures if not using recommended defaults.

Own Id: OTP-17534 Aux Id: GH-5054, PR-5057

Improvements and New Features

When decoding an 'ECPrivateKey' unwrap the private key. For more precise information see RFC 8410, section 7.

Own Id: OTP-17609 Aux Id: GH-5157, GH-5156

Public_Key 1.11.1

Fixed Bugs and Malfunctions

Handle cross-signed root certificates when old root expired as reported in GH-4877.

Own Id: OTP-17475 Aux Id: GH-4877

Public_Key 1.11

Improvements and New Features

TLS connections now support EdDSA certificates.

Own Id: OTP-17142 Aux Id: PR-4756, GH-4637, GH-4650

The functions public_key:ssh_encode/2, public_key:ssh_decode/2, public_key:ssh_hostkey_fingerprint/1 and public_key:ssh_hostkey_fingerprint/2 are deprecated.

Replacement functions are available in SSH, see the Deprecations chapter in the Erlang/OTP documentation.

Own Id: OTP-17352

Enhance documentation and logging of certificate handling.

Own Id: OTP-17384 Aux Id: GH-4800

Public_Key 1.10.0.1

Fixed Bugs and Malfunctions

Handle cross-signed root certificates when old root expired as reported in GH-4877.

Own Id: OTP-17475 Aux Id: GH-4877

Public_Key 1.10

Fixed Bugs and Malfunctions

Fixed case insensitive hostname check.

Own Id: OTP-17242 Aux Id: GH-4500

Improvements and New Features

Add sanity check of trusted anchor certificate expiration to pkix_path_validation/3. Although the anchor is considered a trusted input this sanity check does provide extra security for the users of the public_key application as this property needs to be checked at time of usage and fits very well with the other checks performed here.

Own Id: OTP-16907

Adjust generation of test certificates to conform to RFC 5280 rules for formatting of the certificates validity

Own Id: OTP-17111

Public_Key 1.9.2

Improvements and New Features

Corrected dialyzer spec for pkix_path_validation/3

Own Id: OTP-17069

Public_Key 1.9.1

Fixed Bugs and Malfunctions

Fix the issue that pem_decode will crash with an invalid input.

Own Id: OTP-16902 Aux Id: ERIERL-534

Public_Key 1.9

Fixed Bugs and Malfunctions

Fixed an insignificant whitespace issue when decoding PEM file.

Own Id: OTP-16801 Aux Id: ERL-1309

Improvements and New Features

Experimental OCSP client support.

Own Id: OTP-16448

Use user returned path validation error for selfsigned cert. It allows users of the ssl application to customize the generated TLS alert, within the range of defined alerts.

Own Id: OTP-16592

add API function to retrieve the subject-ID of an X509 certificate

Own Id: OTP-16705

Public_Key 1.8

Improvements and New Features

Added support for RSA-PSS signature schemes

Own Id: OTP-15247

Calls of deprecated functions in the Old Crypto API are replaced by calls of their substitutions.

Own Id: OTP-16346

Public_Key 1.7.2

Improvements and New Features

Add support for key exchange with Edward curves and PSS-RSA padding in signature verification.

Own Id: OTP-16528

Public_Key 1.7.1

Fixed Bugs and Malfunctions

Corrected CRL handling which could cause CRL verification to fail. This could happen when the CRL distribution point explicitly specifies the CRL issuer, that is not using the fallback.

Own Id: OTP-16156 Aux Id: ERL-1030

Public_Key 1.7

Fixed Bugs and Malfunctions

Support Password based encryption with AES

Own Id: OTP-15870 Aux Id: ERL-952

Improvements and New Features

Change dialyzer spec to avoid confusion

Own Id: OTP-15843 Aux Id: ERL-915

Public_Key 1.6.7

Fixed Bugs and Malfunctions

RSA options passed to crypto for encrypt and decrypt with public or private key.

Own Id: OTP-15754 Aux Id: ERL-878

Fix dialyzer warnings caused by a faulty type specification for digest_type().

This change updates digest_type() and the functions operating with this argument type to accept both 'sha1' and 'sha' as digest_type().

Own Id: OTP-15776

Improvements and New Features

Add possibility to read PEM files encrypted with old PEM encryption using AES-256

Own Id: OTP-13726

Relax decoding of certificates to so that "harmless" third party encoding errors may be accepted but not created by the public_key application. This adds acceptance of using an incorrect three character country code, the PKIX standard use two character country codes. It is also accepted that the country code is utf8 encoded but the specification says it should be ASCII.

Own Id: OTP-15687 Aux Id: PR-2162

Public_Key 1.6.6.1

Fixed Bugs and Malfunctions

Support Password based encryption with AES

Own Id: OTP-15870 Aux Id: ERL-952

Public_Key 1.6.6

Improvements and New Features

Back port of bug fix ERL-893 from OTP-22 and document enhancements that will solve dialyzer warnings for users of the ssl application.

This change also affects public_key, eldap (and inet doc).

Own Id: OTP-15785 Aux Id: ERL-929, ERL-893, PR-2215

Public_Key 1.6.5

Improvements and New Features

Add export of dialyzer type

Own Id: OTP-15624

Public_Key 1.6.4

Improvements and New Features

Added ed25519 and ed448 sign/verify.

Requires OpenSSL 1.1.1 or higher as cryptolib under the OTP application crypto.

Own Id: OTP-15419 Aux Id: OTP-15094

Public_Key 1.6.3

Fixed Bugs and Malfunctions

Add DSA SHA2 oids in public_keys ASN1-spec and public_key:pkix_sign_types/1

Own Id: OTP-15367

Public_Key 1.6.2

Fixed Bugs and Malfunctions

Removed #DSAPrivateKey{} as acceptable input to public_key:verify/5.

Own Id: OTP-15284

Improvements and New Features

The typing in the CRYPTO and PUBLIC_KEY applications are reworked and a few mistakes are corrected.

The documentation is now generated from the typing and some clarifications are made.

A new chapter on Algorithm Details such as key sizes and availability is added to the CRYPTO User's Guide.

Own Id: OTP-15134

Public_Key 1.6.1

Fixed Bugs and Malfunctions

Some of the keylengths in the newly generated moduli file in public_key are not universally supported. This could cause the SSH key exchange diffie-hellman-group-exchange-sha* to fail.

Those keylengths are now removed.

Own Id: OTP-15151 Aux Id: OTP-15113

Public_Key 1.6

Fixed Bugs and Malfunctions

Update calls to the base64 module to conform to that module's type specifications.

Own Id: OTP-14788 Aux Id: OTP-14624

Improvements and New Features

Use uri_string module instead of http_uri.

Own Id: OTP-14902

A new function - public_key:pkix_verify_hostname_match_fun/1 - returns a fun to be given as option match_fun to public_key:pkix_verify_hostname/3 or via ssl.

The fun makes the verify hostname matching according to the specific rules for the protocol in the argument. Presently only https is supported.

Own Id: OTP-14962 Aux Id: ERL-542, OTP-15102

Complete PKCS-8 encoding support and enhance the decoding of 'PrivateKeyInfo' to conform to the rest of Erlang public_key API.

Own Id: OTP-15093

A new moduli file is generated. This file is used for the recommended diffie-hellman-group-exchange-sha256 key exchange algorithm in SSH.

Own Id: OTP-15113

Public_Key 1.5.2

Fixed Bugs and Malfunctions

Fixed a bug in public_key:ssh_encode/2 that made it possible to erroneously encode e.g. an RSA key with another type e.g. ECDSA in the resulting binary.

Own Id: OTP-14570 Aux Id: ERIERL-52, OTP-14676

Corrected handling of parameterized EC keys in public_key:generate_key/1 so that it will work as expected instead of causing a runtime error in crypto.

Own Id: OTP-14620

Public_Key 1.5.1

Improvements and New Features

Hostname verification: Add handling of the general name iPAddress in certificate's subject alternative name extension (subjAltName).

Own Id: OTP-14653

Correct key handling in pkix_test_data/1 and use a generic example mail address instead of an existing one.

Own Id: OTP-14766

Public_Key 1.5

Fixed Bugs and Malfunctions

public_key now handles elliptic curve parameters in a consistent way so that decoded ECDSA keys can be correctly re-encoded.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-14621 Aux Id: ERL-480, ERL-481

Improvements and New Features

Extend crypto:sign, crypto:verify, public_key:sign and public_key:verify with:

* support for RSASSA-PS padding for signatures and for saltlength setting
* X9.31 RSA padding.
* sha, sha224, sha256, sha384, and sha512 for dss signatures as mentioned in NIST SP 800-57 Part 1.
* ripemd160 to be used for RSA signatures.

This is a manual merge of half of the pull request 838 by potatosalad from Sept 2015.

Own Id: OTP-13704 Aux Id: PR838

Add API function pkix_test_data/1 for facilitating automated testing. This is useful for applications that perform X509-certifcate path validation of so called certificate chains, such as TLS.

Own Id: OTP-14181

Improved error propagation and reports

Own Id: OTP-14236

RSAPrivateKey version is set to 'two-prime' instead of using the underlying enumeration value directly.

Own Id: OTP-14534

Deprecated function crypto:rand_uniform/2 is replaced by rand:uniform/1.

Own Id: OTP-14608

Public_Key 1.4.1

Fixed Bugs and Malfunctions

Bug for public_key:generate_key({namedCurve,OID}) fixed.

Own Id: OTP-14258

Improvements and New Features

Modernized internal representation used for crl validation by use of maps.

Own Id: OTP-14111

Support EC key in pkix_sign/2

Own Id: OTP-14294

Public_Key 1.4

Improvements and New Features

New function pkix_verify_hostname/2,3 Implements certificate hostname checking. See the manual and RFC 6125.

Own Id: OTP-13009

The ssh host key fingerprint generation now also takes a list of algorithms and returns a list of corresponding fingerprints. See public_key:ssh_hostkey_fingerprint/2 and the option silently_accept_hosts in ssh:connect.

Own Id: OTP-14223

Public_Key 1.3

Improvements and New Features

New function public_key:ssh_hostkey_fingerprint/1,2 to calculate the SSH host key fingerprint string.

Own Id: OTP-13888 Aux Id: OTP-13887

Public_Key 1.2

Fixed Bugs and Malfunctions

The ASN-1 type GeneralName can have more values, then the most common directory name, the code now handles this.

Own Id: OTP-13554

Improvements and New Features

Handle PEM encoded EC public keys

Own Id: OTP-13408

Public_Key 1.1.1

Fixed Bugs and Malfunctions

An encapsulated PEM header shall be followed by a blank line

Own Id: OTP-13381 Aux Id: seq13070

Public_Key 1.1

Improvements and New Features

The 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384' and 'ecdsa-sha2-nistp521' signature algorithms for ssh are implemented. See RFC 5656.

Own Id: OTP-12936

There is now a file (public_key/priv/moduli) which lists size-generator-modulus triples. The purpose is to give servers the possibility to select the crypto primes randomly among a list of pregenerated triples. This reduces the risk for some attacks on diffie-hellman negotiation.

See the reference manual for public_key:dh_gex_group/4 where the handling of this is described.

The ssh server (ssh:daemon) uses this.

Own Id: OTP-13054 Aux Id: OTP-13052

Add different upper bounds for different string types as suggested by comment in PKIX1Explicit88.

Own Id: OTP-13132

Public_Key 1.0.1

Improvements and New Features

Document enhancements

Own Id: OTP-12986

Public_Key 1.0

Improvements and New Features

public_key: Remove legacy switch compact_bit_string

E.i bitstrings will not be decode as {Unused, Binary}, they are now Erlang bitstrings.

Also the compact_bit_string implies the legacy_erlang_types switch So removing the switch will also make OCTET STRING values be represented as binaries.

Undecoded open type will now be wrapped in a asn1_OPENTYPE tuple.

This will change some values in records returned by the public_key API making this change a potentiall incompatibility.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-12110

Public_Key 0.23

Improvements and New Features

Improve/extend support for CRL handling.

Own Id: OTP-12547 Aux Id: OTP-10362

Public_Key 0.22.1

Fixed Bugs and Malfunctions

Added missing encoding support for PBES2, and also completed support for PBES1 that was incomplete.

Own Id: OTP-11915

Public_Key 0.22

Fixed Bugs and Malfunctions

Fix incorrect dialyzer spec and types, also enhance documentation.

Thanks to Ayaz Tuncer.

Own Id: OTP-11627

Application upgrade (appup) files are corrected for the following applications:

asn1, common_test, compiler, crypto, debugger, dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe, inets, observer, odbc, os_mon, otp_mibs, parsetools, percept, public_key, reltool, runtime_tools, ssh, syntax_tools, test_server, tools, typer, webtool, wx, xmerl

A new test utility for testing appup files is added to test_server. This is now used by most applications in OTP.

(Thanks to Tobias Schlager)

Own Id: OTP-11744

Improvements and New Features

Moved elliptic curve definition from the crypto NIF/OpenSSL into Erlang code, adds the RFC-5639 brainpool curves and makes TLS use them (RFC-7027).

Thanks to Andreas Schultz

Own Id: OTP-11578

Handle v1 CRLs, with no extensions and fixes issues with IDP (Issuing Distribution Point) comparison during CRL validation.

Thanks to Andrew Thompson

Own Id: OTP-11761

Public_Key 0.21

Improvements and New Features

Fixed a little typo in public_key documentation. Thanks to Tomas Morstein.

Own Id: OTP-11380

public_key: Workaround for incorrectly encoded utf8 emailAddress. Thanks to Andrew Bennett.

Own Id: OTP-11470

Public_Key 0.20

Improvements and New Features

Extend PKCS-7 to support SCEP (Simple Certificate Enrollment Protocol).

Own Id: OTP-10874

public_key:pem_entry_decode/2 now handles AES-128-CBC ciphered keys. Thanks to Simon Cornish.

Own Id: OTP-11281

Public_Key 0.19

Improvements and New Features

Add support for ISO oids 1.3.14.3.2.29 and 1.3.14.3.2.27 that are sometimes used instead of the PKCS defined oids 1.2.840.113549.1.1.5 and 1.2.840.10040.4.3. Add function pkix_sign_types:/1 that translates oids to to algorithm atoms ex:

public_key:pkix_sign_types({1,3,14,3,2,29}). {sha,rsa}

Own Id: OTP-10873

Integrate elliptic curve contribution from Andreas Schultz

In order to be able to support elliptic curve cipher suites in SSL/TLS, additions to handle elliptic curve infrastructure has been added to public_key and crypto.

This also has resulted in a rewrite of the crypto API to gain consistency and remove unnecessary overhead. All OTP applications using crypto has been updated to use the new API.

Impact: Elliptic curve cryptography (ECC) offers equivalent security with smaller key sizes than other public key algorithms. Smaller key sizes result in savings for power, memory, bandwidth, and computational cost that make ECC especially attractive for constrained environments.

Own Id: OTP-11009

Public_Key 0.18

Fixed Bugs and Malfunctions

Fix subjectPublicKeyInfo type comment in public_key. Thanks to Ryosuke Nakai.

Own Id: OTP-10670

Improvements and New Features

public_key now supports CRL validation and documents the function public_key:pkix_path_validation/3

Own Id: OTP-7045

Some examples overflowing the width of PDF pages have been corrected.

Own Id: OTP-10665

Fixed typo's in public_key spec.

Own Id: OTP-10723

Corrected PKCS-10 documentation and added some PKCS-9 support that is fairly commonly used by PKCS-10. Full support for PKCS-9 will be added later.

Own Id: OTP-10767

Public_Key 0.17

Fixed Bugs and Malfunctions

ssh_decode now handles comments, at the end of the line, containing with spaces correctly

Own Id: OTP-9361

Add missing references to sha224 and sha384

Own Id: OTP-9362 Aux Id: seq12116

Improvements and New Features

public_key now supports PKCS-10 and includes experimental support for PKCS-7

Own Id: OTP-10509 Aux Id: kunagi-291 [202]

Public_Key 0.16

Improvements and New Features

Add crypto and public_key support for the hash functions SHA224, SHA256, SHA384 and SHA512 and also hmac and rsa_sign/verify support using these hash functions. Thanks to Andreas Schultz for making a prototype.

Own Id: OTP-9908

Optimize RSA private key handling in crypto and public_key.

Own Id: OTP-10065

Public_Key 0.15

Improvements and New Features

Changed ssh implementation to use the public_key application for all public key handling. This is also a first step for enabling a callback API for supplying public keys and handling keys protected with password phrases.

Additionally the test suites where improved so that they do not copy the users keys to test server directories as this is a security liability. Also ipv6 and file access issues found in the process has been fixed.

This change also solves OTP-7677 and OTP-7235

This changes also involves some updates to public_keys ssh-functions.

Own Id: OTP-9911

Public_Key 0.14

Improvements and New Features

public_key, ssl and crypto now supports PKCS-8

Own Id: OTP-9312

The asn1 decoder/encoder now uses a runtime nif from the asn1 application if it is available.

Own Id: OTP-9414

Public_Key 0.13

Fixed Bugs and Malfunctions

replace "a ssl" with "an ssl" reindent pkix_path_validation/3 Trivial documentation fixes (Thanks to Christian von Roques )

Own Id: OTP-9464

Public_Key 0.12

Improvements and New Features

The public_key application now supports encode/decode of ssh public-key files.

Own Id: OTP-9144

Public_Key 0.11

Improvements and New Features

Allows the public_key module to decode and encode RSA and DSA keys encoded using the SubjectPublicKeyInfo format. When pem_entry_encode is called on an RSA or DSA public key type, the key is wrapped in the SubjectPublicKeyInfo format.

Own Id: OTP-9061

Public_Key 0.10

Improvements and New Features

Improved dialyzer specs.

Own Id: OTP-8964

Public_Key 0.9

Improvements and New Features

Updated ssl to ignore CA certs that violate the asn1-spec for a certificate, and updated public key asn1 spec to handle inherited DSS-params.

Own Id: OTP-7884

Changed ssl implementation to retain backwards compatibility for old option {verify, 0} that shall be equivalent to {verify, verify_none}, also separate the cases unknown ca and selfsigned peer cert, and restored return value of deprecated function public_key:pem_to_der/1.

Own Id: OTP-8858

Better handling of v1 and v2 certificates. V1 and v2 certificates does not have any extensions so then validate_extensions should just accept that there are none and not end up in missing_basic_constraints clause.

Own Id: OTP-8867

Changed the verify fun so that it differentiate between the peer certificate and CA certificates by using valid_peer or valid as the second argument to the verify fun. It may not always be trivial or even possible to know when the peer certificate is reached otherwise.

* POTENTIAL INCOMPATIBILITY *

Own Id: OTP-8873

Public_Key 0.8

Fixed Bugs and Malfunctions

Handling of unknown CA certificates was changed in ssl and public_key to work as intended.

Own Id: OTP-8788

Improvements and New Features

Revise the public_key API - Cleaned up and documented the public_key API to make it useful for general use, also changed ssl to use the new API.

Own Id: OTP-8722

Added the functionality so that the verification fun will be called when a certificate is considered valid by the path validation to allow access to each certificate in the path to the user application. Also try to verify subject-AltName, if unable to verify it let the application verify it.

Own Id: OTP-8825

Public_Key 0.7

Fixed Bugs and Malfunctions

Certificates without any extensions could not be handled by public_key.

Own Id: OTP-8626

Improvements and New Features

Code cleanup and minor bugfixes.

Own Id: OTP-8649

Public_Key 0.6

Improvements and New Features

Support for Diffie-Hellman. ssl-3.11 requires public_key-0.6.

Own Id: OTP-7046

Moved extended key usage test for ssl values to ssl.

Own Id: OTP-8553 Aux Id: seq11541, OTP-8554

Public_Key 0.5

Improvements and New Features

Added public_key:pkix_transform/2 to enable ssl to send CA list during Certificate Request.

NOTE: SSL (new_ssl) requires public_key-0.5. ssl usage.

Own Id: OTP-8372

Public_Key 0.4

Improvements and New Features

The documentation is now built with open source tools (xsltproc and fop) that exists on most platforms. One visible change is that the frames are removed.

Own Id: OTP-8250

Public_Key 0.3

Fixed Bugs and Malfunctions

Unknown attributes in certificates are left encoded instead of crashing. Patch by Will "wglozer" thanks.

Own Id: OTP-8100

Improvements and New Features

Allow public_key:pem_to_der/[1,2] to take a binary as argument in addition to a filename. Patch by Geoff Cant, thanks.

Own Id: OTP-8142

Public_Key 0.2

Improvements and New Features

X509 certificate handling has been extended and improved as a result of more extensive testing of both the ssl and public_key application. Even more extensions of the certificate handling is yet to be implemented.

Own Id: OTP-7860

Public_Key 0.1

Improvements and New Features

First version.

Own Id: OTP-7637

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").

Data Types

Common non-standard Erlang data types used to describe the record fields in the following sections and which are not defined in the Public Key Reference Manual follows here:

time() = utc_time() | general_time()

utc_time()  = {utcTime, "YYMMDDHHMMSSZ"}

general_time() = {generalTime, "YYYYMMDDHHMMSSZ"}

general_name() = {rfc822Name, string()} |

                 {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 |
                cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise

OID_macro() = ?OID_name()

OID_name() = atom()

RSA

Erlang representation of Rivest-Shamir-Adleman cryptosystem (RSA) keys follows:

#'RSAPublicKey'{
   modulus,       % pos_integer()
   publicExponent % pos_integer()
  }.

#'RSAPrivateKey'{
   version,         % two-prime | multi
   modulus,         % pos_integer()
   publicExponent,  % pos_integer()
   privateExponent, % pos_integer()
   prime1,          % pos_integer()
   prime2,          % pos_integer()
   exponent1,       % pos_integer()
   exponent2,       % pos_integer()
   coefficient,     % pos_integer()
   otherPrimeInfos  % [#OtherPrimeInfo{}] | asn1_NOVALUE
  }.

#'OtherPrimeInfo'{
   prime,           % pos_integer()
   exponent,        % pos_integer()
   coefficient      % pos_integer()
  }.

#'RSASSA-PSS-params'{
   hashAlgorithm,     % #'HashAlgorithm'{}},
   maskGenAlgorithm,  % #'MaskGenAlgorithm'{}},
   saltLength,        % pos_integer(),
   trailerField,      % pos_integer()
  }.

#'HashAlgorithm'{
   algorithm,  % oid()
   parameters  % defaults to asn1_NOVALUE
  }.

#'MaskGenAlgorithm'{
   algorithm,  % oid()
   parameters, % defaults to asn1_NOVALUE
  }.

DSA

Erlang representation of Digital Signature Algorithm (DSA) keys

#'DSAPrivateKey'{
   version,      % pos_integer()
   p,            % pos_integer()
   q,            % pos_integer()
   g,            % pos_integer()
   y,            % pos_integer()
   x             % pos_integer()
  }.

#'Dss-Parms'{
   p,         % pos_integer()
   q,         % pos_integer()
   g          % pos_integer()
  }.

ECDSA and EDDSA

Erlang representation of Elliptic Curve Digital Signature Algorithm (ECDSA) and Edwards-Curve Digital Signature Algorithm (EDDSA) where parameters in the private key will be {namedCurve, ?'id-Ed25519' | ?'id-Ed448'}.

#'ECPrivateKey'{
   version,       % pos_integer() |  ecPrivkeyVer1 (enumeration value, decode returns atom, encode accepts both)
   privateKey,    % binary()
   parameters,    % {ecParameters, #'ECParameters'{}} | - Legacy
                  % {namedCurve, Oid::tuple()} |
                  % {implicitlyCA, 'NULL'}
   publicKey      % bitstring()
  }.

%% Legacy no longer defined in current PKIX standard
#'ECParameters'{
   version,    % pos_integer() | v1 (enumeration value)
   fieldID,    % #'FieldID'{}
   curve,      % #'Curve'{}
   base,       % binary()
   order,      % pos_integer()
   cofactor    % pos_integer()
  }.

#'Curve'{
   a,        % binary()
   b,        % binary()
   seed      % bitstring() - optional
  }.

#'FieldID'{
   fieldType,    % oid()
   parameters    % Depending on fieldType
  }.

#'ECPoint'{
   point %  binary() - the public key
  }.

PKIX Certificates

Erlang representation of PKIX certificates derived from ASN.1 specifications see also X509 certificates (RFC 5280), also referred to as plain type, are as follows:

#'Certificate'{
   tbsCertificate,        % #'TBSCertificate'{}
   signatureAlgorithm,    % #'AlgorithmIdentifier'{}
   signature              % bitstring()
  }.

#'TBSCertificate'{
   version,              % v1 | v2 | v3
   serialNumber,         % pos_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()
  }.

Erlang alternate representation of PKIX certificate, also referred to as otp type

#'OTPCertificate'{
   tbsCertificate,        % #'OTPTBSCertificate'{}
   signatureAlgorithm,    % #'SignatureAlgorithm'
   signature              % bitstring()
  }.

#'OTPTBSCertificate'{
   version,              % v1 | v2 | v3
   serialNumber,         % pos_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

id-dsaWithSHA1 (ISO or OID to above)

md2WithRSAEncryption

md5WithRSAEncryption

sha1WithRSAEncryption

sha-1WithRSAEncryption (ISO or OID to above)

sha224WithRSAEncryption

sha256WithRSAEncryption

sha512WithRSAEncryption

ecdsa-with-SHA1

Table: Signature Algorithm OIDs

The data type 'AttributeTypeAndValue', is represented as the following erlang record:

#'AttributeTypeAndValue'{
   type,   % id_attributes()
   value   % term()
  }.

The attribute OID name atoms and their corresponding value types are as follows:

OID Name | Value Type
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-dnQualifier | {printableString, string()}
id-at-countryName | {printableString, string()}
id-at-serialNumber | {printableString, string()}
id-at-pseudonym | special_string()

Table: Attribute OIDs

The data types 'Validity', 'SubjectPublicKeyInfo', and 'SubjectPublicKeyInfoAlgorithm' are represented as the following Erlang records:

#'Validity'{
   notBefore, % time()
   notAfter   % time()
  }.

#'SubjectPublicKeyInfo'{
   algorithm,       % #AlgorithmIdentifier{}
   subjectPublicKey % binary()
  }.

#'SubjectPublicKeyInfoAlgorithm'{
   algorithm,  % id_public_key_algorithm()
   parameters  % public_key_params()
  }.

The public-key algorithm OID name atoms are as follows:

OID Name

rsaEncryption

id-dsa

dhpublicnumber

id-keyExchangeAlgorithm

id-ecPublicKey

Table: Public-Key Algorithm OIDs

#'Extension'{
   extnID,    % id_extensions() | oid()
   critical,  % boolean()
   extnValue  % der_encoded()
  }.

id_extensions() Standard Certificate Extensions, Private Internet Extensions, CRL Extensions and CRL Entry Extensions.

PKIXCMP Certificate Management Protocol

Erlang representation of PKIXCMP see PKIXCMP.hrl, some of the records defined.

-record('PKIMessage', {
   header,     % #'PKIHeader'{}
   body,       % #'PKIBody'{}
   protection, % Optional #'PKIProtection'{}
   extraCerts  % Optional [#'CMPCertificate'{}]
  }).

PKIXCRMF Certificate Request Message Format

Erlang representation of PKIXCRMF see PKIXCRMF.hrl, some of the records defined.

-record('CertReqMsg', {
    certReq,     % #'CertRequest'{}
    popo,        % Optional choice
    regInfo      % [#'CertReqMsg_reginfo_SEQOF'{}]
   }).

-record('CertRequest', {
    certReqId    % integer,
    certTemplate % #'CertTemplate'{}
    controls     % #'Controls_SEQOF'{}
   }).

Standard Certificate Extensions

The standard certificate extensions OID name atoms and their corresponding value types are as follows:

OID Name | Value Type
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 | pos_integer()
id-ce-freshestCRL | [#'DistributionPoint'{}]

Table: Standard Certificate Extensions

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

Table: Key Purpose OIDs

#'AuthorityKeyIdentifier'{
   keyIdentifier,            % oid()
   authorityCertIssuer,      % general_name()
   authorityCertSerialNumber % pos_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    % [pos_integer()]
  }.

#'PolicyMappings_SEQOF'{
   issuerDomainPolicy,  % oid()
   subjectDomainPolicy  % oid()
  }.

#'Attribute'{
   type,  % oid()
   values % [der_encoded()]
  }).

#'BasicConstraints'{
   cA,               % boolean()
   pathLenConstraint % pos_integer()
  }).

#'NameConstraints'{
   permittedSubtrees, % [#'GeneralSubtree'{}]
   excludedSubtrees   % [#'GeneralSubtree'{}]
  }).

#'GeneralSubtree'{
   base,    % general_name()
   minimum, % pos_integer()
   maximum  % pos_integer()
  }).

#'PolicyConstraints'{
   requireExplicitPolicy, % pos_integer()
   inhibitPolicyMapping   % pos_integer()
  }).

#'DistributionPoint'{
   distributionPoint, % {fullName, [general_name()]} | {nameRelativeToCRLIssuer,[#AttributeTypeAndValue{}]}
   reasons,           % [dist_reason()]
   cRLIssuer          % [general_name()]
  }).

Private Internet Extensions

The private internet extensions OID name atoms and their corresponding value types are as follows:

OID Name | Value Type
id-pe-authorityInfoAccess | [#'AccessDescription'{}]
id-pe-subjectInfoAccess | [#'AccessDescription'{}]

Table: Private Internet Extensions

#'AccessDescription'{
   accessMethod,    % oid()
   accessLocation   % general_name()
  }).

CRL and CRL Extensions Profile

Erlang representation of CRL and CRL extensions profile derived from ASN.1 specifications and RFC 5280 are as follows:

#'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,      % pos_integer()
   revocationDate,       % timer()
   crlEntryExtensions    % [#'Extension'{}]
  }).

CRL Extensions

The CRL extensions OID name atoms and their corresponding value types are as follows:

OID Name | Value Type
id-ce-authorityKeyIdentifier | #'AuthorityKeyIdentifier{}
id-ce-issuerAltName | {rdnSequence, [#AttributeTypeAndValue'{}]}
id-ce-cRLNumber | pos_integer()
id-ce-deltaCRLIndicator | pos_integer()
id-ce-issuingDistributionPoint | #'IssuingDistributionPoint'{}
id-ce-freshestCRL | [#'Distributionpoint'{}]

Table: CRL Extensions

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()
  }).

CRL Entry Extensions

The CRL entry extensions OID name atoms and their corresponding value types are as follows:

OID Name | Value Type
id-ce-cRLReason | crl_reason()
id-ce-holdInstructionCode | oid()
id-ce-invalidityDate | general_time()
id-ce-certificateIssuer | general_name()

Table: CRL Entry Extensions

Here:

    crl_reason() = unspecified | keyCompromise | cACompromise
                 | affiliationChanged | superseded | cessationOfOperation
                 | certificateHold | removeFromCRL
                 | privilegeWithdrawn | aACompromise

PKCS#10 Certification Request

Erlang representation of a PKCS#10 certification request derived from ASN.1 specifications and RFC 5280 are as follows:

#'CertificationRequest'{
   certificationRequestInfo, % #'CertificationRequestInfo'{},
   signatureAlgorithm,       % #'CertificationRequest_signatureAlgorithm'{}}.
   signature                 % bitstring()
  }.

#'CertificationRequestInfo'{
   version,       % atom(),
   subject,       % {rdnSequence, [#AttributeTypeAndValue'{}]} ,
   subjectPKInfo, % #'CertificationRequestInfo_subjectPKInfo'{},
   attributes     % [#'Attribute' {}]
  }.

#'CertificationRequestInfo_subjectPKInfo'{
   algorithm,        % #'CertificationRequestInfo_subjectPKInfo_algorithm'{}
   subjectPublicKey  %  bitstring()
  }.

#'CertificationRequestInfo_subjectPKInfo_algorithm'{
   algorithm,  % oid(),
   parameters  % der_encoded()
  }.

#'CertificationRequest_signatureAlgorithm'{
   algorithm,  % oid(),
   parameters  % der_encoded()
  }.

#'Attribute'{
   type,   % oid(),
   values  % [der_encoded()]
  }.

Examples

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.

PEM Files

Public-key data (keys, certificates, and so on) can be stored in Privacy Enhanced Mail (PEM) format. The PEM files have the following structure:

    <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.

DSA Private Key

A DSA private key can look as follows:

Note

File handling is not done by the Public Key application.

1> {ok, PemBin} = file:read_file("dsa.pem").
{ok,<<"-----BEGIN DSA PRIVATE KEY-----\nMIIBuw"...>>}

The following PEM file has only one entry, a private DSA key:

2>[DSAEntry] =  public_key:pem_decode(PemBin).
[{'DSAPrivateKey',<<48,130,1,187,2,1,0,2,129,129,0,183,
                    179,230,217,37,99,144,157,21,228,204,
                    162,207,61,246,...>>,
                    not_encrypted}]

3> Key = public_key:pem_entry_decode(DSAEntry).
#'DSAPrivateKey'{version = 0,
                 p = 12900045185019966618...6593,
                 q = 1216700114794736143432235288305776850295620488937,
                 g = 10442040227452349332...47213,
                 y = 87256807980030509074...403143,
                 x = 510968529856012146351317363807366575075645839654}

RSA Private Key with Password

An RSA private key encrypted with a password can look as follows:

1> {ok, PemBin} = file:read_file("rsa.pem").
{ok,<<"Bag Attribute"...>>}

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">>}}]

In this following example, the password is "abcd1234":

3> Key = public_key:pem_entry_decode(RSAEntry, "abcd1234").
#'RSAPrivateKey'{version = 'two-prime',
                 modulus = 1112355156729921663373...2737107,
                 publicExponent = 65537,
                 privateExponent = 58064406231183...2239766033,
                 prime1 = 11034766614656598484098...7326883017,
                 prime2 = 10080459293561036618240...77738643771,
                 exponent1 = 77928819327425934607...22152984217,
                 exponent2 = 36287623121853605733...20588523793,
                 coefficient = 924840412626098444...41820968343,
                 otherPrimeInfos = asn1_NOVALUE}

X509 Certificates

The following is an example of X509 certificates:

1> {ok, PemBin} = file:read_file("cacerts.pem").
{ok,<<"-----BEGIN CERTIFICATE-----\nMIIC7jCCAl"...>>}

The following file includes two certificates:

2> [CertEntry1, CertEntry2] = public_key:pem_decode(PemBin).
[{'Certificate',<<48,130,2,238,48,130,2,87,160,3,2,1,2,2,
                  9,0,230,145,97,214,191,2,120,150,48,13,
                  ...>>,
                not_encrypted},
 {'Certificate',<<48,130,3,200,48,130,3,49,160,3,2,1,2,2,1,
                  1,48,13,6,9,42,134,72,134,247,...>>,
                not_encrypted}]

Certificates can be decoded as usual:

2> Cert = public_key:pem_entry_decode(CertEntry1).
#'Certificate'{
    tbsCertificate =
        #'TBSCertificate'{
            version = v3,serialNumber = 16614168075301976214,
            signature =
                #'AlgorithmIdentifier'{
                    algorithm = {1,2,840,113549,1,1,5},
                    parameters = <<5,0>>},
            issuer =
                {rdnSequence,
                    [[#'AttributeTypeAndValue'{
                          type = {2,5,4,3},
                          value = <<19,8,101,114,108,97,110,103,67,65>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,11},
                          value = <<19,10,69,114,108,97,110,103,32,79,84,80>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,10},
                          value = <<19,11,69,114,105,99,115,115,111,110,32,65,66>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,7},
                          value = <<19,9,83,116,111,99,107,104,111,108,109>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,6},
                          value = <<19,2,83,69>>}],
                     [#'AttributeTypeAndValue'{
                          type = {1,2,840,113549,1,9,1},
                          value = <<22,22,112,101,116,101,114,64,101,114,...>>}]]},
            validity =
                #'Validity'{
                    notBefore = {utcTime,"080109082929Z"},
                    notAfter = {utcTime,"080208082929Z"}},
            subject =
                {rdnSequence,
                    [[#'AttributeTypeAndValue'{
                          type = {2,5,4,3},
                          value = <<19,8,101,114,108,97,110,103,67,65>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,11},
                          value = <<19,10,69,114,108,97,110,103,32,79,84,80>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,10},
                          value = <<19,11,69,114,105,99,115,115,111,110,32,...>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,7},
                          value = <<19,9,83,116,111,99,107,104,111,108,...>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,6},
                          value = <<19,2,83,69>>}],
                     [#'AttributeTypeAndValue'{
                          type = {1,2,840,113549,1,9,1},
                          value = <<22,22,112,101,116,101,114,64,...>>}]]},
            subjectPublicKeyInfo =
                #'SubjectPublicKeyInfo'{
                    algorithm =
                        #'AlgorithmIdentifier'{
                            algorithm = {1,2,840,113549,1,1,1},
                            parameters = <<5,0>>},
                    subjectPublicKey =
                        {0,<<48,129,137,2,129,129,0,203,209,187,77,73,231,90,...>>}},
            issuerUniqueID = asn1_NOVALUE,
            subjectUniqueID = asn1_NOVALUE,
            extensions =
                [#'Extension'{
                     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:

3> {_, DerCert, _} = CertEntry1.

4> public_key:pkix_decode_cert(DerCert, otp).
#'OTPCertificate'{
    tbsCertificate =
        #'OTPTBSCertificate'{
            version = v3,serialNumber = 16614168075301976214,
            signature =
                #'SignatureAlgorithm'{
                    algorithm = {1,2,840,113549,1,1,5},
                    parameters = 'NULL'},
            issuer =
                {rdnSequence,
                    [[#'AttributeTypeAndValue'{
                          type = {2,5,4,3},
                          value = {printableString,"erlangCA"}}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,11},
                          value = {printableString,"Erlang OTP"}}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,10},
                          value = {printableString,"Ericsson AB"}}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,7},
                          value = {printableString,"Stockholm"}}],
                     [#'AttributeTypeAndValue'{type = {2,5,4,6},value = "SE"}],
                     [#'AttributeTypeAndValue'{
                          type = {1,2,840,113549,1,9,1},
                          value = "peter@erix.ericsson.se"}]]},
            validity =
                #'Validity'{
                    notBefore = {utcTime,"080109082929Z"},
                    notAfter = {utcTime,"080208082929Z"}},
            subject =
                {rdnSequence,
                    [[#'AttributeTypeAndValue'{
                          type = {2,5,4,3},
                          value = {printableString,"erlangCA"}}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,11},
                          value = {printableString,"Erlang OTP"}}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,10},
                          value = {printableString,"Ericsson AB"}}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,7},
                          value = {printableString,"Stockholm"}}],
                     [#'AttributeTypeAndValue'{type = {2,5,4,6},value = "SE"}],
                     [#'AttributeTypeAndValue'{
                          type = {1,2,840,113549,1,9,1},
                          value = "peter@erix.ericsson.se"}]]},
            subjectPublicKeyInfo =
                #'OTPSubjectPublicKeyInfo'{
                    algorithm =
                        #'PublicKeyAlgorithm'{
                            algorithm = {1,2,840,113549,1,1,1},
                            parameters = 'NULL'},
                    subjectPublicKey =
                        #'RSAPublicKey'{
                            modulus =
                                1431267547247997...37419,
                            publicExponent = 65537}},
            issuerUniqueID = asn1_NOVALUE,
            subjectUniqueID = asn1_NOVALUE,
            extensions =
                [#'Extension'{
                     extnID = {2,5,29,19},
                     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,...>>}

This call is equivalent to public_key:pem_entry_decode(CertEntry1):

5> public_key:pkix_decode_cert(DerCert, plain).
#'Certificate'{ ...}

Encoding Public-Key Data to PEM Format

If you have public-key data and want to create a PEM file this can be done by calling functions public_key:pem_entry_encode/2 and pem_encode/1 and saving the result to a file. For example, assume that you have PubKey = 'RSAPublicKey'{}. Then you can create a PEM-"RSA PUBLIC KEY" file (ASN.1 type 'RSAPublicKey') or a PEM-"PUBLIC KEY" file ('SubjectPublicKeyInfo' ASN.1 type).

The second element of the PEM-entry is the ASN.1 DER encoded key data:

1> PemEntry = public_key:pem_entry_encode('RSAPublicKey', RSAPubKey).
{'RSAPublicKey', <<48,72,...>>, not_encrypted}

2> PemBin = public_key:pem_encode([PemEntry]).
<<"-----BEGIN RSA PUBLIC KEY-----\nMEgC...>>

3> file:write_file("rsa_pub_key.pem", PemBin).
ok

or:

1> PemEntry = public_key:pem_entry_encode('SubjectPublicKeyInfo', RSAPubKey).
{'SubjectPublicKeyInfo', <<48,92...>>, not_encrypted}

2> PemBin = public_key:pem_encode([PemEntry]).
<<"-----BEGIN PUBLIC KEY-----\nMFw...>>

3> file:write_file("pub_key.pem", PemBin).
ok

RSA Public-Key Cryptography

Suppose you have the following private key and a corresponding public key:

PrivateKey = #'RSAPrivateKey{}' and the plaintext Msg = binary()

PublicKey = #'RSAPublicKey'{}

Then you can proceed as follows:

Encrypt with the private key:

RsaEncrypted = public_key:encrypt_private(Msg, PrivateKey),
Msg = public_key:decrypt_public(RsaEncrypted, PublicKey),

Encrypt with the public key:

RsaEncrypted = public_key:encrypt_public(Msg, PublicKey),
Msg = public_key:decrypt_private(RsaEncrypted, PrivateKey),

Note

You normally do only one of the encrypt or decrypt operations, and the peer does the other. This normally used in legacy applications as a primitive digital signature.

Warning

This legacy algorithm is broken although there exists a software prevention when using appropriate OpenSSL cryptolib with Erlang/OTP it is hard to guarantee security and we strongly recommend not using it.

Digital Signatures

Suppose you have the following private key and a corresponding public key:

PrivateKey = #'RSAPrivateKey{}' or #'DSAPrivateKey'{} and the plaintext Msg = binary()

PublicKey = #'RSAPublicKey'{} or {integer(), #'DssParams'{}}

Then you can proceed as follows:

Signature = public_key:sign(Msg, sha, PrivateKey),
true = public_key:verify(Msg, sha, Signature, PublicKey),

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),

Verifying a certificate hostname

Background

When a client checks a server certificate there are a number of checks available like checks that the certificate is not revoked, not forged or not out-of-date.

There are however attacks that are not detected by those checks. Suppose a bad guy has succeeded with a DNS infection. Then the client could believe it is connecting to one host but ends up at another but evil one. Though it is evil, it could have a perfectly legal certificate! The certificate has a valid signature, it is not revoked, the certificate chain is not faked and has a trusted root and so on.

To detect that the server is not the intended one, the client must additionally perform a hostname verification. This procedure is described in RFC 6125. The idea is that the certificate lists the hostnames it could be fetched from. This 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 believes 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 acquire the Reference IDs.

Internationalized domain names are not supported.

The verification process

Traditionally the Presented IDs were found in the Subject certificate field as CN names. This is still quite common. When printing a certificate they show up as:

 $ openssl x509 -text < cert.pem
 ...
 Subject: C=SE, CN=example.com, CN=*.example.com, O=erlang.org
 ...

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:

 $ openssl x509 -text < cert.pem
 ...
 X509v3 extensions:
     X509v3 Subject Alternative Name:
         DNS:kb.example.org, URI:https://www.example.org
 ...

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:

 $ openssl x509 -text < cert.pem
 ...
 Subject: C=SE, CN=example.com, CN=*.example.com, O=erlang.org
 ...
 X509v3 extensions:
     X509v3 Subject Alternative Name:
         DNS:kb.example.org, URI:https://www.example.org
 ...

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 because they are in the Subject field which is not checked because the Subject Alternate Name field is present.

Function call examples

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()}.

Extending the search mechanism

The caller can use own extraction and matching rules. This is done with the two options fqdn_fun and match_fun.

Hostname extraction

The fqdn_fun extracts hostnames (Fully Qualified Domain Names) from uri_id or other ReferenceIDs that are not pre-defined in the public_key function. Suppose you have some URI with a very special protocol-part: myspecial://example.com". Since this a non-standard URI there will be no hostname extracted for matching CN-names in the Subject.

To "teach" the function how to extract, you can give a fun which replaces the default extraction function. The fqdn_fun takes one argument and returns either a string/0 to be matched to each CN-name or the atom default which will invoke the default fqdn extraction function. The return value undefined removes the current URI from the fqdn extraction.

 ...
 Extract = fun({uri_id, "myspecial://"++HostName}) -> HostName;
              (_Else) -> default
           end,
 ...
 public_key:pkix_verify_hostname(CertFromHost, RefIDs,
                                 [{fqdn_fun, Extract}])
 ...

Re-defining the match operation

The default matching handles dns_id and uri_id. In an uri_id the value is tested for equality with a value from the Subject Alternate Name. If some other kind of matching is needed, use the match_fun option.

The match_fun takes two arguments and returns either true, false or default. The value default will invoke the default match function.

 ...
 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 transformation applied to the strings. The reason is to enable the user to do unforeseen 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:

 -include_lib("public_key/include/public_key.hrl"). % Record def
 ...
 Fail = fun(#'OTPCertificate'{}=C) ->
              case in_my_cache(C) orelse my_accept(C) of
                  true ->
                       enter_my_cache(C),
                       true;
                  false ->
                       false
         end,
 ...
 public_key:pkix_verify_hostname(CertFromHost, RefIDs,
                                 [{fail_callback, Fail}]),
 ...

public_key

API module for public-key infrastructure.

Provides functions to handle public-key infrastructure, for details see public_key application.

Note

All records used in this Reference Manual are generated from ASN.1 specifications and are documented in the User's Guide. See Public-key Records.

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").

Summary

Types: Certificate Revocation

crl_reason()

The reason that a certifcate has been revoked as define by RFC 5280.

Types: Certificates

bad_cert_reason()

The reason that a certifcate gets rejected by the certificate path validation.

cert()

An encoded or decode certificate.

cert_id()

A certificate is identified by its serial-number and Issuer Name.

combined_cert()

A record that can be used to provide the certificate on both the DER encoded and the OTP decode format.

issuer_name()

The value of the issuer part of a certificate.

policy_node()

Certificate policy information.

public_key_info()

Information a certificates public key.

Types: Common

asn1_type()

ASN.1 type present in the Public Key applications ASN.1 specifications.

der_encoded()

ASN.1 DER encoded entity.

digest_type()

Hash function used to create a message digest

oid()

Object identifier, a tuple of integers as generated by the ASN.1 compiler.

Types: Keys

custom_key_opts()

Can be provided together with a custom private key, that specifies a key fun, to provide additional options understood by the fun.

dsa_private_key()

ASN.1 defined private key format for the DSA algorithm.

dsa_public_key()

ASN.1 defined public key format for the DSA algorithm.

dss_public_key()

ASN.1 defined public key format for the DSS algorithm (part of DSA key).

ecdsa_public_key()

ASN.1 defined public key format for the ECDSA algorithm.

eddsa_private_key()

ASN.1 defined private key format for the EDDSA algorithm, possible oids: ?'id-Ed25519' | ?'id-Ed448'

eddsa_public_key()

ASN.1 defined public key format for the EDDSA algorithm, possible oids: ?'id-Ed25519' | ?'id-Ed448'

public_key()

Supported public keys

rsa_private_key()

ASN.1 defined private key format plain RSA algorithm or customization fun.

rsa_pss_private_key()

ASN.1 defined private key format the RSSASSA-PSS algorithm or customization fun.

rsa_pss_public_key()

ASN.1 defined public key format for the RSSASSA-PSS algorithm.

rsa_public_key()

ASN.1 defined public key format for plain RSA algorithm.

Types: PEM files

pem_entry()

Possible Ciphers are "RC2-CBC" | "DES-CBC" | "DES-EDE3-CBC" Salt could be generated with crypto:strong_rand_bytes(8).

pki_asn1_type()

ASN.1 type that can be found in PEM files that can be decode by the public_key application.

Types: Test Data

cert_opt()

Options to customize generated test certificates

chain_opts()

Certificate customize options for diffrent parts of the certificate test chain.

conf_opt()

Configuration options for the generated certificate test chain.

Types

ecdsa_private_key()

ASN.1 defined private key format for the ECDSA algorithm.

key_params()

ASN.1 defined parameters for public key algorithms.

legacy_digest_type()

mldsa_private_key()

ML-DSA private key

mldsa_public_key()

ML-DSA public key

private_key()

Supported private keys

slh_dsa_private_key()

SLH-DSA private key

slh_dsa_public_key()

SLH-DSA public key

ASN.1 Encoding API

der_decode(Asn1Type, Der)

Decodes a public-key ASN.1 DER encoded entity.

der_encode(Asn1Type, Entity)

Encodes a public-key entity with ASN.1 DER encoding.

Certificate API

cacerts_clear()

Clears any loaded CA certificates, returns true if any was loaded.

cacerts_get()

Returns the trusted CA certificates if any are loaded, otherwise uses cacerts_load/0 to load them. The function fails if no cacerts could be loaded.

cacerts_load()

Loads the OS supplied trusted CA certificates.

cacerts_load(File)

Loads the trusted CA certificates from a file.

pkix_decode_cert(Cert, Type)

Decodes an ASN.1 DER-encoded PKIX certificate.

pkix_encode(Asn1Type, Entity, Type)

DER encodes a PKIX x509 certificate or part of such a certificate.

pkix_hash_type(HashOid)

Translates OID to Erlang digest type

pkix_is_fixed_dh_cert(Cert)

Checks if a certificate is a fixed Diffie-Hellman certificate.

pkix_is_issuer(CertorCRL, IssuerCert)

Checks if IssuerCert issued Cert.

pkix_is_self_signed(Cert)

Checks if a certificate is self-signed.

pkix_issuer_id(Cert, IssuedBy)

Returns the x509 certificate issuer id, if it can be determined.

pkix_normalize_name(Issuer)

Normalizes an issuer name so that it can be easily compared to another issuer name.

pkix_path_validation(Cert, CertChain, Options)

Performs a basic path validation according to RFC 5280.

pkix_sign_types(AlgorithmId)

Translates signature algorithm OID to Erlang digest and signature types.

pkix_subject_id(Cert)

Returns the X509 certificate subject id.

pkix_verify_hostname(Cert, ReferenceIDs)

Equivalent to pkix_verify_hostname(Cert, ReferenceIDs, []).

pkix_verify_hostname(Cert, ReferenceIDs, Options)

This function checks that the Presented Identifier (e.g hostname) in a peer certificate is in agreement with at least one of the Reference Identifier that the client expects to be connected to.

pkix_verify_hostname_match_fun(Protocol)

The return value of calling this function is intended to be used in the match_fun option in pkix_verify_hostname/3.

Certificate Revocation API

pkix_crl_issuer(CRL)

Returns the issuer of the CRL.

pkix_crl_verify(CRL, Cert)

Verify that Cert is the CRL signer.

pkix_crls_validate(OTPcertificate, DPandCRLs, Options)

Performs CRL validation. It is intended to be called from the verify fun of pkix_path_validation/3 .

pkix_dist_point(Cert)

Creates a distribution point for CRLs issued by the same issuer as Cert. Can be used as input to pkix_crls_validate/3

pkix_dist_points(Cert)

Extracts distribution points from the certificates extensions.

pkix_match_dist_point(CRL, DistPoint)

Checks whether the given distribution point matches the Issuing Distribution Point of the CRL, as described in RFC 5280.

pkix_ocsp_validate(Cert, IssuerCert, OcspRespDer, NonceExt, Options)

Perform OCSP response validation according to RFC 6960. Returns {'ok', Details} when OCSP response is successfully validated and {error, {bad_cert, Reason}} otherwise.

short_name_hash(Name)

Generates a short hash of an issuer name. The hash is returned as a string containing eight hexadecimal digits.

Key API

compute_key(OthersECDHkey, MyECDHkey)

Computes shared secret.

compute_key(OthersDHkey, MyDHkey, DHparms)

Computes shared secret.

dh_gex_group(MinSize, SuggestedSize, MaxSize, Groups)

Selects a group for Diffie-Hellman key exchange with the key size in the range MinSize...MaxSize and as close to SuggestedSize as possible. If Groups == undefined a default set will be used, otherwise the group is selected from Groups.

generate_key/1

Generates a new key pair. Note that except for Diffie-Hellman the public key is included in the private key structure. See also crypto:generate_key/2

Legacy RSA Encryption API

decrypt_private(CipherText, Key)

Equivalent to decrypt_private(CipherText, Key, []).

decrypt_private(CipherText, Key, Options)

Public-key decryption using the private key. See also crypto:private_decrypt/4

decrypt_public(CipherText, Key)

Equivalent to decrypt_public(CipherText, Key, []).

decrypt_public(CipherText, Key, Options)

Public-key decryption using the public key. See also crypto:public_decrypt/4

encrypt_private(PlainText, Key)

Equivalent to encrypt_private(PlainText, Key, []).

encrypt_private(PlainText, Key, Options)

Public-key encryption using the private key.

encrypt_public(PlainText, Key)

Equivalent to encrypt_public(PlainText, Key, []).

encrypt_public(PlainText, Key, Options)

Public-key encryption using the public key. See also crypto:public_encrypt/4.

PEM API

pem_decode(PemBin)

Decodes PEM binary data and returns entries as ASN.1 DER encoded entities.

pem_encode(PemEntries)

Creates a PEM binary.

pem_entry_decode(PemEntry)

Equivalent to pem_entry_decode(PemEntry, "").

pem_entry_decode(PemEntry, Password)

Decodes a PEM entry. pem_decode/1 returns a list of PEM entries. Notice that if the PEM entry is of type 'SubjectPublickeyInfo', it is further decoded to an rsa_public_key/0 or dsa_public_key/0.

pem_entry_encode(Asn1Type, Entity)

Equivalent to pem_entry_encode/3.

pem_entry_encode(Asn1Type, Entity, InfoPwd)

Creates a PEM entry that can be feed to pem_encode/1.

Sign/Verify API

pkix_sign(Cert, Key)

Signs an 'OTPTBSCertificate'. Returns the corresponding DER-encoded certificate.

pkix_verify(Cert, Key)

Verifies PKIX x.509 certificate signature.

sign(Msg, DigestType, Key)

Equivalent to sign(Msg, DigestType, Key, []).

sign(Msg, DigestType, Key, Options)

Creates a digital signature.

verify(Msg, DigestType, Signature, Key)

Equivalent to verify(Msg, DigestType, Signature, Key, []).

verify(Msg, DigestType, Signature, Key, Options)

Verifies a digital signature.

Test Data API

pkix_test_data(ChainConf)

Creates certificate configuration(s) consisting of certificate and its private key plus CA certificate bundle, for a client and a server, intended to facilitate automated testing of applications using X509-certificates, often through SSL/TLS. The test data can be used when you have control over both the client and the server in a test scenario.

pkix_test_root_cert(Name, Options)

Generates a root certificate that can be used in multiple calls to pkix_test_data/1 when you want the same root certificate for several generated certificates.

Types: Certificate Revocation

crl_reason()

(not exported)

-type crl_reason() ::
          unspecified | keyCompromise | cACompromise | affiliationChanged | superseded |
          cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise.

The reason that a certifcate has been revoked as define by RFC 5280.

Types: Certificates

bad_cert_reason()

-type bad_cert_reason() ::
          cert_expired | invalid_issuer | invalid_signature | name_not_permitted |
          missing_basic_constraint | invalid_key_usage | duplicate_cert_in_path |
          {key_usage_mismatch, term()} |
          {policy_requirement_not_met, term()} |
          {invalid_policy_mapping, term()} |
          {revoked, crl_reason()} |
          invalid_validity_dates |
          {revocation_status_undetermined, term()} |
          atom().

The reason that a certifcate gets rejected by the certificate path validation.

cert()

-type cert() ::
          der_encoded() |
          #'OTPCertificate'{tbsCertificate :: term(), signatureAlgorithm :: term(), signature :: term()}.

An encoded or decode certificate.

cert_id()

-type cert_id() :: {SerialNr :: integer(), issuer_name()}.

A certificate is identified by its serial-number and Issuer Name.

combined_cert()

-type combined_cert() ::
          #cert{der :: public_key:der_encoded(),
                otp ::
                    #'OTPCertificate'{tbsCertificate :: term(),
                                      signatureAlgorithm :: term(),
                                      signature :: term()}}.

A record that can be used to provide the certificate on both the DER encoded and the OTP decode format.

Such a construct can be useful to avoid conversions and problems that can arise due to relaxed decoding rules.

issuer_name()

-type issuer_name() :: {rdnSequence, [[#'AttributeTypeAndValue'{type :: term(), value :: term()}]]}.

The value of the issuer part of a certificate.

policy_node()

-type policy_node() ::
          #{valid_policy := oid(),
            qualifier_set :=
                [#'UserNotice'{noticeRef :: term(), explicitText :: term()} | {uri, string()}],
            expected_policy_set := [oid()]}.

Certificate policy information.

public_key_info()

-type public_key_info() ::
          {oid(), rsa_public_key() | #'ECPoint'{point :: term()} | dss_public_key(), key_params()}.

Information a certificates public key.

Possible oids: ?'rsaEncryption' | ?'id-RSASSA-PSS' | ?'id-ecPublicKey' | ?'id-Ed25519' | ?'id-Ed448' | ?'id-dsa'

Types: Common

asn1_type()

-type asn1_type() :: atom().

ASN.1 type present in the Public Key applications ASN.1 specifications.

der_encoded()

-type der_encoded() :: binary().

ASN.1 DER encoded entity.

digest_type()

-type digest_type() :: crypto:sha2() | crypto:sha1() | legacy_digest_type() | none.

Hash function used to create a message digest

oid()

-type oid() :: tuple().

Object identifier, a tuple of integers as generated by the ASN.1 compiler.

Types: Keys

custom_key_opts()

-type custom_key_opts() :: [term()].

Can be provided together with a custom private key, that specifies a key fun, to provide additional options understood by the fun.

dsa_private_key()

-type dsa_private_key() ::
          #'DSAPrivateKey'{version :: term(),
                           p :: term(),
                           q :: term(),
                           g :: term(),
                           y :: term(),
                           x :: term()}.

ASN.1 defined private key format for the DSA algorithm.

dsa_public_key()

-type dsa_public_key() :: {dss_public_key(), #'Dss-Parms'{p :: term(), q :: term(), g :: term()}}.

ASN.1 defined public key format for the DSA algorithm.

dss_public_key()

(not exported)

-type dss_public_key() :: pos_integer().

ASN.1 defined public key format for the DSS algorithm (part of DSA key).

ecdsa_public_key()

-type ecdsa_public_key() ::
          {#'ECPoint'{point :: term()},
           {namedCurve, oid()} |
           #'ECParameters'{version :: term(),
                           fieldID :: term(),
                           curve :: term(),
                           base :: term(),
                           order :: term(),
                           cofactor :: term()}}.

ASN.1 defined public key format for the ECDSA algorithm.

eddsa_private_key()

-type eddsa_private_key() ::
          #'ECPrivateKey'{parameters :: {namedCurve, oid()},
                          version :: term(),
                          privateKey :: term(),
                          publicKey :: term(),
                          attributes :: term()}.

ASN.1 defined private key format for the EDDSA algorithm, possible oids: ?'id-Ed25519' | ?'id-Ed448'

eddsa_public_key()

-type eddsa_public_key() :: {#'ECPoint'{point :: term()}, {namedCurve, oid()}}.

ASN.1 defined public key format for the EDDSA algorithm, possible oids: ?'id-Ed25519' | ?'id-Ed448'

public_key()

-type public_key() ::
          rsa_public_key() |
          rsa_pss_public_key() |
          dsa_public_key() |
          ecdsa_public_key() |
          eddsa_public_key() |
          mldsa_public_key() |
          slh_dsa_public_key().

Supported public keys

rsa_private_key()

-type rsa_private_key() ::
          #'RSAPrivateKey'{version :: term(),
                           modulus :: term(),
                           publicExponent :: term(),
                           privateExponent :: term(),
                           prime1 :: term(),
                           prime2 :: term(),
                           exponent1 :: term(),
                           exponent2 :: term(),
                           coefficient :: term(),
                           otherPrimeInfos :: term()} |
          #{algorithm := rsa, encrypt_fun => fun()}.

ASN.1 defined private key format plain RSA algorithm or customization fun.

rsa_pss_private_key()

-type rsa_pss_private_key() ::
          {#'RSAPrivateKey'{version :: term(),
                            modulus :: term(),
                            publicExponent :: term(),
                            privateExponent :: term(),
                            prime1 :: term(),
                            prime2 :: term(),
                            exponent1 :: term(),
                            exponent2 :: term(),
                            coefficient :: term(),
                            otherPrimeInfos :: term()},
           #'RSASSA-PSS-params'{hashAlgorithm :: term(),
                                maskGenAlgorithm :: term(),
                                saltLength :: term(),
                                trailerField :: term()}}.

ASN.1 defined private key format the RSSASSA-PSS algorithm or customization fun.

rsa_pss_public_key()

-type rsa_pss_public_key() ::
          {rsa_public_key(),
           #'RSASSA-PSS-params'{hashAlgorithm :: term(),
                                maskGenAlgorithm :: term(),
                                saltLength :: term(),
                                trailerField :: term()}}.

ASN.1 defined public key format for the RSSASSA-PSS algorithm.

rsa_public_key()

-type rsa_public_key() :: #'RSAPublicKey'{modulus :: term(), publicExponent :: term()}.

ASN.1 defined public key format for plain RSA algorithm.

Types: PEM files

pem_entry()

-type pem_entry() ::
          {pki_asn1_type(),
           DerOrDerEncrypted :: binary(),
           not_encrypted |
           {Cipher :: iodata(),
            Salt ::
                binary() |
                {#'PBEParameter'{salt :: term(), iterationCount :: term()}, digest_type()} |
                #'PBES2-params'{keyDerivationFunc :: term(), encryptionScheme :: term()}}}.

Possible Ciphers are "RC2-CBC" | "DES-CBC" | "DES-EDE3-CBC" Salt could be generated with crypto:strong_rand_bytes(8).

pki_asn1_type()

-type pki_asn1_type() ::
          'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey' | 'SubjectPublicKeyInfo' | 'DSAPrivateKey' |
          'DHParameter' | 'PrivateKeyInfo' | 'CertificationRequest' | 'ContentInfo' |
          'CertificateList' | 'ECPrivateKey' | 'OneAsymmetricKey' | 'EcpkParameters'.

ASN.1 type that can be found in PEM files that can be decode by the public_key application.

Types: Test Data

cert_opt()

-type cert_opt() ::
          {digest, digest_type()} |
          {key,
           {namedCurve, oid()} |
           #'ECParameters'{version :: term(),
                           fieldID :: term(),
                           curve :: term(),
                           base :: term(),
                           order :: term(),
                           cofactor :: term()} |
           {rsa, Size :: pos_integer(), Prime :: pos_integer()} |
           private_key()} |
          {validity, {From :: erlang:timestamp(), To :: erlang:timestamp()}} |
          {extensions, [#'Extension'{extnID :: term(), critical :: term(), extnValue :: term()}]}.

Options to customize generated test certificates

chain_opts()

-type chain_opts() :: #{root := [cert_opt()], intermediates => [[cert_opt()]], peer := [cert_opt()]}.

Certificate customize options for diffrent parts of the certificate test chain.

conf_opt()

-type conf_opt() ::
          {cert, der_encoded()} |
          {key, private_key() | {both, public_key(), private_key()}} |
          {cacerts, [der_encoded()]}.

Configuration options for the generated certificate test chain.

Types

ecdsa_private_key()

-type ecdsa_private_key() ::
          #'ECPrivateKey'{version :: term(),
                          privateKey :: term(),
                          parameters :: term(),
                          publicKey :: term(),
                          attributes :: term()}.

ASN.1 defined private key format for the ECDSA algorithm.

key_params()

-type key_params() ::
          'NULL' |
          #'RSASSA-PSS-params'{hashAlgorithm :: term(),
                               maskGenAlgorithm :: term(),
                               saltLength :: term(),
                               trailerField :: term()} |
          {namedCurve, oid()} |
          #'ECParameters'{version :: term(),
                          fieldID :: term(),
                          curve :: term(),
                          base :: term(),
                          order :: term(),
                          cofactor :: term()} |
          #'Dss-Parms'{p :: term(), q :: term(), g :: term()}.

ASN.1 defined parameters for public key algorithms.

legacy_digest_type()

(not exported)

-type legacy_digest_type() :: md5 | md2.

mldsa_private_key()

-type mldsa_private_key() ::
          #'ML-DSAPrivateKey'{algorithm :: crypto:mldsa(), seed :: binary(), expandedkey :: binary()}.

ML-DSA private key

mldsa_public_key()

-type mldsa_public_key() :: #'ML-DSAPublicKey'{algorithm :: crypto:mldsa(), key :: binary()}.

ML-DSA public key

private_key()

-type private_key() ::
          rsa_private_key() |
          rsa_pss_private_key() |
          dsa_private_key() |
          ecdsa_private_key() |
          eddsa_private_key() |
          mldsa_private_key() |
          slh_dsa_private_key() |
          #{algorithm := slh_dsa | mldsa | eddsa | rsa_pss_pss | ecdsa | rsa | dsa, sign_fun => fun()}.

Supported private keys

slh_dsa_private_key()

-type slh_dsa_private_key() :: #'SLH-DSAPrivateKey'{algorithm :: crypto:slh_dsa(), key :: binary()}.

SLH-DSA private key

slh_dsa_public_key()

-type slh_dsa_public_key() :: #'SLH-DSAPublicKey'{algorithm :: crypto:slh_dsa(), key :: binary()}.

SLH-DSA public key

ASN.1 Encoding API

der_decode(Asn1Type, Der)

(since OTP R14B)

-spec der_decode(Asn1Type, Der) -> Entity
                    when Asn1Type :: asn1_type(), Der :: der_encoded(), Entity :: term().

Decodes a public-key ASN.1 DER encoded entity.

der_encode(Asn1Type, Entity)

(since OTP R14B)

-spec der_encode(Asn1Type, Entity) -> Der
                    when Asn1Type :: asn1_type(), Entity :: term(), Der :: binary().

Encodes a public-key entity with ASN.1 DER encoding.

Certificate API

cacerts_clear()

(since OTP 25.0)

-spec cacerts_clear() -> boolean().

Clears any loaded CA certificates, returns true if any was loaded.

cacerts_get()

(since OTP 25.0)

-spec cacerts_get() -> [combined_cert()].

Returns the trusted CA certificates if any are loaded, otherwise uses cacerts_load/0 to load them. The function fails if no cacerts could be loaded.

cacerts_load()

(since OTP 25.0)

-spec cacerts_load() -> ok | {error, Reason :: term()}.

Loads the OS supplied trusted CA certificates.

This can be overridden by setting the cacerts_path environment key of the public_key application with the location of an alternative certificate. You can set it via the command line as:

erl -public_key cacerts_path '"/path/to/certs.pem"'

Use it with care. It is your responsibility to ensure that the certificates found in this alternative path can be trusted by the running system.

cacerts_load(File)

(since OTP 25.0)

-spec cacerts_load(File :: file:filename_all()) -> ok | {error, Reason :: term()}.

Loads the trusted CA certificates from a file.

pkix_decode_cert(Cert, Type)

-spec pkix_decode_cert(Cert, Type) ->
                          #'Certificate'{toBeSigned :: term(),
                                         algorithmIdentifier :: term(),
                                         signature :: term()} |
                          #'OTPCertificate'{tbsCertificate :: term(),
                                            signatureAlgorithm :: term(),
                                            signature :: term()}
                          when Cert :: der_encoded(), Type :: plain | otp | relaxed.

Decodes an ASN.1 DER-encoded PKIX certificate.

Option otp uses the customized ASN.1 specification OTP-PKIX.asn1 for decoding and also recursively decode most of the standard parts.

Option relaxed is similar to option otp but also allows for empty RDNs in issuer and subject.

pkix_encode(Asn1Type, Entity, Type)

(since OTP R14B)

-spec pkix_encode(Asn1Type, Entity, Type) -> Der
                     when
                         Asn1Type :: asn1_type(),
                         Entity :: term(),
                         Type :: otp | plain,
                         Der :: der_encoded().

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 directly calls der_encode/2.

Note

Subtle ASN-1 encoding errors in certificates may be worked around when decoding, this may have the affect that the encoding a certificate back to DER may generate different bytes then the supplied original.

pkix_hash_type(HashOid)

(since OTP 23.0)

-spec pkix_hash_type(HashOid :: oid()) -> DigestType :: digest_type().

Translates OID to Erlang digest type

pkix_is_fixed_dh_cert(Cert)

(since OTP R14B)

-spec pkix_is_fixed_dh_cert(Cert) -> boolean() when Cert :: cert().

Checks if a certificate is a fixed Diffie-Hellman certificate.

pkix_is_issuer(CertorCRL, IssuerCert)

(since OTP R14B)

-spec pkix_is_issuer(CertorCRL, IssuerCert) -> boolean()
                        when
                            CertorCRL ::
                                cert() |
                                #'CertificateList'{toBeSigned :: term(),
                                                   algorithmIdentifier :: term(),
                                                   signature :: term()},
                            IssuerCert :: cert().

Checks if IssuerCert issued Cert.

pkix_is_self_signed(Cert)

(since OTP R14B)

-spec pkix_is_self_signed(Cert) -> boolean() when Cert :: cert().

Checks if a certificate is self-signed.

pkix_issuer_id(Cert, IssuedBy)

(since OTP R14B)

-spec pkix_issuer_id(Cert, IssuedBy) -> {ok, ID :: cert_id()} | {error, Reason}
                        when Cert :: cert(), IssuedBy :: self | other, Reason :: term().

Returns the x509 certificate issuer id, if it can be determined.

pkix_normalize_name(Issuer)

(since OTP R14B)

-spec pkix_normalize_name(Issuer) -> Normalized
                             when Issuer :: issuer_name() | der_encoded(), Normalized :: issuer_name().

Normalizes an issuer name so that it can be easily compared to another issuer name.

pkix_path_validation(Cert, CertChain, Options)

(since OTP R16B)

-spec pkix_path_validation(Cert, CertChain, Options) ->
                              {ok, {PublicKeyInfo, ConstrainedPolicyNodes}} |
                              {error, {bad_cert, Reason :: bad_cert_reason()}}
                              when
                                  Cert :: cert() | combined_cert() | atom(),
                                  CertChain :: [cert() | combined_cert()],
                                  Options ::
                                      [{max_path_length, integer()} | {verify_fun, {fun(), term()}}],
                                  PublicKeyInfo :: public_key_info(),
                                  ConstrainedPolicyNodes :: [policy_node()].

Performs a basic path validation according to RFC 5280.

However, CRL validation is done separately by pkix_crls_validate/3 and is to be called from the supplied verify_fun. The policy tree check was added in OTP-26.2 and if the certificates include policies the constrained policy set with potential qualifiers will be returned, these values are derived from the policy tree created as part of the path validation algorithm. The constrained set can be constrained only by the Certificate Authorities or also by the user when the option policy_set is provided to this function. The qualifiers convey information about the valid policy and is intended as information to end users.

Available options:

{verify_fun, {fun(), UserState::term()} - The fun must be defined as:

fun(OtpCert :: #'OTPCertificate'{},
    Event :: {bad_cert, Reason :: bad_cert_reason() | {revoked, atom()}} |
             {extension, #'Extension'{}},
    UserState :: term()) ->
  {valid, UserState :: term()} |
  {valid_peer, UserState :: term()} |
  {fail, Reason :: term()} |
  {unknown, UserState :: term()}.

or as:

fun(OtpCert :: #'OTPCertificate'{},
    DerCert :: der_encoded(),
    Event :: {bad_cert, Reason :: bad_cert_reason() | {revoked, atom()}} |
             {extension, #'Extension'{}},
    UserState :: term()) ->
  {valid, UserState :: term()} |
  {valid_peer, UserState :: term()} |
  {fail, Reason :: term()} |
  {unknown, UserState :: term()}.

The verify callback can have 3 or 4 arguments in case the DER encoded version is needed by the callback.

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.

Note

If you need the DER encoded version of the certificate and have the OTP decoded version encoding it back can fail to give the correct result, due to work arounds for common misbehaving encoders. So it is recommended to call pkix_path_validation with Cert and CertChain arguments as der_encoded() | #cert{} and [der_encoded() | #cert{}]. Also note that the path validation itself needs both the encoded and the decoded version of the certificate.

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.

{policy_set, [oid()]}(Since OTP 26.2)
The set of policies that will be accepted, defaults to the special value [?anyPolicy] that will accept all policies.

{explicit_policy, boolean()}(Since OTP 26.2)
Explicitly require that each certificate in the path must include at least one of the certificate policies in the policy_set.

{inhibit_policy_mapping, boolean()}(Since OTP 26.2)
Prevent policies to be mapped to other policies.

{inhibit_any_policy, boolean()}(Since OTP 26.2)
Prevent the special policy ?anyPolicy from being accepted.

Explanations of 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.

invalid_validity_dates - The validity section of the X.509 certificate(s) contains invalid date formats not matching the RFC.

atom() - Application-specific error reason that is to be checked by the verify_fun.

pkix_sign_types(AlgorithmId)

(since OTP R16B01)

-spec pkix_sign_types(AlgorithmId) -> {DigestType, SignatureType}
                         when
                             AlgorithmId :: oid(),
                             DigestType :: digest_type(),
                             SignatureType ::
                                 rsa | dsa | ecdsa | eddsa | crypto:mldsa() | crypto:slh_dsa().

Translates signature algorithm OID to Erlang digest and signature types.

The AlgorithmId is the signature OID from a certificate or a certificate revocation list.

pkix_subject_id(Cert)

(since OTP 23.1)

-spec pkix_subject_id(Cert) -> ID when Cert :: cert(), ID :: cert_id().

Returns the X509 certificate subject id.

pkix_verify_hostname(Cert, ReferenceIDs)

(since OTP 19.3)

-spec pkix_verify_hostname(Cert, ReferenceIDs) -> boolean()
                              when
                                  Cert :: cert(),
                                  ReferenceIDs ::
                                      [{uri_id | dns_id | ip | srv_id | atom() | oid(), string()} |
                                       {ip, inet:ip_address() | string()}].

Equivalent to pkix_verify_hostname(Cert, ReferenceIDs, []).

pkix_verify_hostname(Cert, ReferenceIDs, Options)

(since OTP 19.3)

-spec pkix_verify_hostname(Cert, ReferenceIDs, Options) -> boolean()
                              when
                                  Cert :: cert(),
                                  ReferenceIDs ::
                                      [{uri_id | dns_id | ip | srv_id | atom() | oid(), string()} |
                                       {ip, inet:ip_address() | string()}],
                                  Options :: [{match_fun | fail_callback | fqdn_fun, fun()}].

This function checks that the Presented Identifier (e.g hostname) in a peer certificate is in agreement with at least one of the Reference Identifier that the client expects to be connected to.

The function is intended to be added as an extra client check of the peer certificate when performing public_key:pkix_path_validation/3

See RFC 6125 for detailed information about hostname verification. The User's Guide and code examples describes this function more detailed.

The option funs are described here:

match_fun

fun(ReferenceId::ReferenceId() | FQDN::string(),
    PresentedId::{dNSName,string()} | {uniformResourceIdentifier,string() |
                 {iPAddress,list(byte())} | {OtherId::atom()|oid(),term()}})

This function replaces the default host name matching rules. The fun should return a boolean to tell if the Reference ID and Presented ID matches or not. The match fun can also return a third value, value, the atom default, if the default matching rules shall apply. This makes it possible to augment the tests with a special case:

fun(....) -> true;   % My special case
   (_, _) -> default % all others falls back to the inherit tests
end

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.

Note

Reference Id values given as binaries will be converted to strings, and ip references may be given in string format that is "10.0.1.1" or "1234::5678:9012" as well as on the format inet:ip_address/0

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 an exception but for hostnames. This fun/1 is called when no ReferenceID matches. The return value of the fun (a boolean/0) 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.

pkix_verify_hostname_match_fun(Protocol)

(since OTP 21.0)

-spec pkix_verify_hostname_match_fun(Protocol) -> Result when Protocol :: https, Result :: fun().

The return value of calling this function is intended to be used in the match_fun option in pkix_verify_hostname/3.

The returned fun augments the verify hostname matching according to the specific rules for the protocol in the argument.

Note

Currently supported https fun will allow wildcard certificate matching as specified by the HTTP standard. Note that for instance LDAP have a different set of wildcard matching rules. If you do not want to allow wildcard certificates (recommended from a security perspective) or otherwise customize the hostname match the default match function used by ssl application will be sufficient.

Certificate Revocation API

pkix_crl_issuer(CRL)

(since OTP 17.5)

-spec pkix_crl_issuer(CRL) -> Issuer
                         when
                             CRL ::
                                 der_encoded() |
                                 #'CertificateList'{toBeSigned :: term(),
                                                    algorithmIdentifier :: term(),
                                                    signature :: term()},
                             Issuer :: issuer_name().

Returns the issuer of the CRL.

pkix_crl_verify(CRL, Cert)

(since OTP 17.5)

-spec pkix_crl_verify(CRL, Cert) -> boolean()
                         when
                             CRL ::
                                 der_encoded() |
                                 #'CertificateList'{toBeSigned :: term(),
                                                    algorithmIdentifier :: term(),
                                                    signature :: term()},
                             Cert :: cert().

Verify that Cert is the CRL signer.

pkix_crls_validate(OTPcertificate, DPandCRLs, Options)

(since OTP R16B)

-spec pkix_crls_validate(OTPcertificate, DPandCRLs, Options) -> CRLstatus
                            when
                                OTPcertificate ::
                                    #'OTPCertificate'{tbsCertificate :: term(),
                                                      signatureAlgorithm :: term(),
                                                      signature :: term()},
                                DPandCRLs :: [DPandCRL],
                                DPandCRL :: {DP, {DerCRL, CRL}},
                                DP ::
                                    #'DistributionPoint'{distributionPoint :: term(),
                                                         reasons :: term(),
                                                         cRLIssuer :: term()},
                                DerCRL :: der_encoded(),
                                CRL ::
                                    #'CertificateList'{toBeSigned :: term(),
                                                       algorithmIdentifier :: term(),
                                                       signature :: term()},
                                Options :: [{atom(), term()}],
                                CRLstatus :: valid | {bad_cert, BadCertReason},
                                BadCertReason ::
                                    revocation_status_undetermined |
                                    {revocation_status_undetermined, Reason :: term()} |
                                    {revoked, crl_reason()}.

Performs CRL validation. It is intended to be called from the verify fun of pkix_path_validation/3 .

Available options:

{update_crl, fun()} - The fun has the following type specification:

 fun(#'DistributionPoint'{}, #'CertificateList'{}) ->
        #'CertificateList'{}

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:

 fun(_DP, CRL) -> CRL end

{issuer_fun, {fun(), UserState::term()}} - The fun has the following type specification:

fun(#'DistributionPoint'{}, #'CertificateList'{},
    {rdnSequence,[#'AttributeTypeAndValue'{}]}, UserState::term()) ->
  {ok, #'OTPCertificate'{}, [der_encoded]}

The fun returns the root certificate and certificate chain that has signed the CRL.

 fun(DP, CRL, Issuer, UserState) -> {ok, RootCert, CertChain}

{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.

pkix_dist_point(Cert)

(since OTP 17.5)

-spec pkix_dist_point(Cert) -> DistPoint
                         when
                             Cert :: cert(),
                             DistPoint ::
                                 #'DistributionPoint'{distributionPoint :: term(),
                                                      reasons :: term(),
                                                      cRLIssuer :: term()}.

Creates a distribution point for CRLs issued by the same issuer as Cert. Can be used as input to pkix_crls_validate/3

pkix_dist_points(Cert)

(since OTP 17.5)

-spec pkix_dist_points(Cert) -> DistPoints
                          when
                              Cert :: cert(),
                              DistPoints ::
                                  [#'DistributionPoint'{distributionPoint :: term(),
                                                        reasons :: term(),
                                                        cRLIssuer :: term()}].

Extracts distribution points from the certificates extensions.

pkix_match_dist_point(CRL, DistPoint)

(since OTP 19.0)

-spec pkix_match_dist_point(CRL, DistPoint) -> boolean()
                               when
                                   CRL ::
                                       der_encoded() |
                                       #'CertificateList'{toBeSigned :: term(),
                                                          algorithmIdentifier :: term(),
                                                          signature :: term()},
                                   DistPoint ::
                                       #'DistributionPoint'{distributionPoint :: term(),
                                                            reasons :: term(),
                                                            cRLIssuer :: term()}.

Checks whether the given distribution point matches the Issuing Distribution Point of the CRL, as described in RFC 5280.

If the CRL doesn't have an Issuing Distribution Point extension, the distribution point always matches.

pkix_ocsp_validate(Cert, IssuerCert, OcspRespDer, NonceExt, Options)

(since OTP 27.0)

-spec pkix_ocsp_validate(Cert, IssuerCert, OcspRespDer, NonceExt, Options) ->
                            {ok, Details} | {error, {bad_cert, Reason}}
                            when
                                Cert :: cert(),
                                IssuerCert :: cert(),
                                OcspRespDer :: der_encoded(),
                                NonceExt :: undefined | binary(),
                                Options ::
                                    [{is_trusted_responder_fun, fun((combined_cert()) -> boolean)}],
                                Details :: list(),
                                Reason :: bad_cert_reason().

Perform OCSP response validation according to RFC 6960. Returns {'ok', Details} when OCSP response is successfully validated and {error, {bad_cert, Reason}} otherwise.

Available options:

{is_trusted_responder_fun, fun()} - The fun has the following type specification:

 fun(#cert{}) ->
    boolean()

The fun returns the true if certificate in the argument is trusted. If this fun is not specified, Public Key uses the default implementation:

 fun(_) -> false end

Note

OCSP response can be provided without a nonce value - even if it was requested by the client. In such cases {missing, ocsp_nonce} will be returned in Details list.

short_name_hash(Name)

(since OTP 19.0)

-spec short_name_hash(Name) -> string() when Name :: issuer_name().

Generates a short hash of an issuer name. The hash is returned as a string containing eight hexadecimal digits.

The return value of this function is the same as the result of the commands openssl crl -hash and openssl x509 -issuer_hash, when passed the issuer name of a CRL or a certificate, respectively. This hash is used by the c_rehash tool to maintain a directory of symlinks to CRL files, in order to facilitate looking up a CRL by its issuer name.

Key API

compute_key(OthersECDHkey, MyECDHkey)

(since OTP R16B01)

-spec compute_key(OthersECDHkey, MyECDHkey) -> SharedSecret
                     when
                         OthersECDHkey :: #'ECPoint'{point :: term()},
                         MyECDHkey ::
                             #'ECPrivateKey'{version :: term(),
                                             privateKey :: term(),
                                             parameters :: term(),
                                             publicKey :: term(),
                                             attributes :: term()},
                         SharedSecret :: binary().

Computes shared secret.

compute_key(OthersDHkey, MyDHkey, DHparms)

(since OTP R16B01)

-spec compute_key(OthersDHkey, MyDHkey, DHparms) -> SharedSecret
                     when
                         OthersDHkey :: crypto:dh_public(),
                         MyDHkey :: crypto:dh_private(),
                         DHparms ::
                             #'DHParameter'{prime :: term(),
                                            base :: term(),
                                            privateValueLength :: term()},
                         SharedSecret :: binary().

Computes shared secret.

dh_gex_group(MinSize, SuggestedSize, MaxSize, Groups)

(since OTP 18.2)

-spec dh_gex_group(MinSize, SuggestedSize, MaxSize, Groups) -> {ok, {Size, Group}} | {error, term()}
                      when
                          MinSize :: pos_integer(),
                          SuggestedSize :: pos_integer(),
                          MaxSize :: pos_integer(),
                          Groups :: undefined | [{Size, [Group]}],
                          Size :: pos_integer(),
                          Group :: {G, P},
                          G :: pos_integer(),
                          P :: pos_integer().

Selects a group for Diffie-Hellman key exchange with the key size in the range MinSize...MaxSize and as close to SuggestedSize as possible. If Groups == undefined a default set will be used, otherwise the group is selected from Groups.

First a size, as close as possible to SuggestedSize, is selected. Then one group with that key size is randomly selected from the specified set of groups. If no size within the limits of MinSize and MaxSize is available, {error,no_group_found} is returned.

The default set of groups is listed in lib/public_key/priv/moduli. This file may be regenerated like this:

	$> 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

generate_key/1

(since OTP R16B01)

-spec generate_key(DHparams | ECparams | RSAparams | MLDSA | SLHDSA) ->
                      DHkeys | ECkey | RSAkey | MLDSAKeys | SLHDSAKeys
                      when
                          DHparams ::
                              #'DHParameter'{prime :: term(),
                                             base :: term(),
                                             privateValueLength :: term()},
                          DHkeys :: {PublicDH :: binary(), PrivateDH :: binary()},
                          ECparams ::
                              {namedCurve, oid() | atom()} |
                              #'ECParameters'{version :: term(),
                                              fieldID :: term(),
                                              curve :: term(),
                                              base :: term(),
                                              order :: term(),
                                              cofactor :: term()},
                          ECkey ::
                              #'ECPrivateKey'{version :: term(),
                                              privateKey :: term(),
                                              parameters :: term(),
                                              publicKey :: term(),
                                              attributes :: term()},
                          RSAparams :: {rsa, Size, PubExp},
                          Size :: pos_integer(),
                          PubExp :: pos_integer(),
                          RSAkey ::
                              #'RSAPrivateKey'{version :: term(),
                                               modulus :: term(),
                                               publicExponent :: term(),
                                               privateExponent :: term(),
                                               prime1 :: term(),
                                               prime2 :: term(),
                                               exponent1 :: term(),
                                               exponent2 :: term(),
                                               coefficient :: term(),
                                               otherPrimeInfos :: term()},
                          MLDSA :: crypto:mldsa(),
                          MLDSAKeys ::
                              {#'ML-DSAPublicKey'{algorithm :: crypto:mldsa(), key :: binary()},
                               #'ML-DSAPrivateKey'{algorithm :: crypto:mldsa(),
                                                   seed :: binary(),
                                                   expandedkey :: binary()}},
                          SLHDSA :: crypto:slh_dsa(),
                          SLHDSAKeys ::
                              {#'SLH-DSAPublicKey'{algorithm :: crypto:slh_dsa(), key :: binary()},
                               #'SLH-DSAPrivateKey'{algorithm :: crypto:slh_dsa(), key :: binary()}}.

Generates a new key pair. Note that except for Diffie-Hellman the public key is included in the private key structure. See also crypto:generate_key/2

Legacy RSA Encryption API

decrypt_private(CipherText, Key)

(since OTP R14B)

-spec decrypt_private(CipherText, Key) -> PlainText
                         when CipherText :: binary(), Key :: rsa_private_key(), PlainText :: binary().

Equivalent to decrypt_private(CipherText, Key, []).

decrypt_private(CipherText, Key, Options)

(since OTP R14B)

-spec decrypt_private(CipherText, Key, Options) -> PlainText
                         when
                             CipherText :: binary(),
                             Key :: rsa_private_key(),
                             Options :: crypto:pk_encrypt_decrypt_opts(),
                             PlainText :: binary().

Public-key decryption using the private key. See also crypto:private_decrypt/4

Warning

This is a legacy function, for security reasons do not use with rsa_pkcs1_padding.

decrypt_public(CipherText, Key)

(since OTP R14B)

-spec decrypt_public(CipherText, Key) -> PlainText
                        when CipherText :: binary(), Key :: rsa_public_key(), PlainText :: binary().

Equivalent to decrypt_public(CipherText, Key, []).

decrypt_public(CipherText, Key, Options)

(since OTP R14B)

-spec decrypt_public(CipherText, Key, Options) -> PlainText
                        when
                            CipherText :: binary(),
                            Key :: rsa_public_key(),
                            Options :: crypto:pk_encrypt_decrypt_opts(),
                            PlainText :: binary().

Public-key decryption using the public key. See also crypto:public_decrypt/4

Warning

This is a legacy function, for security reasons do not use with rsa_pkcs1_padding. For digital signatures the use of verify/4 together with sign/3 is a prefered solution.

encrypt_private(PlainText, Key)

(since OTP R14B)

-spec encrypt_private(PlainText, Key) -> CipherText
                         when PlainText :: binary(), Key :: rsa_private_key(), CipherText :: binary().

Equivalent to encrypt_private(PlainText, Key, []).

encrypt_private(PlainText, Key, Options)

(since OTP 21.1)

-spec encrypt_private(PlainText, Key, Options) -> CipherText
                         when
                             PlainText :: binary(),
                             Key :: rsa_private_key(),
                             Options :: crypto:pk_encrypt_decrypt_opts() | custom_key_opts(),
                             CipherText :: binary().

Public-key encryption using the private key.

See also crypto:private_encrypt/4. The key can, besides a standard RSA key, be a map specifing the key algorithm rsa and a fun to handle the encryption operation. This may be used for customized the encryption operation with for instance hardware security modules (HSM) or trusted platform modules (TPM).

Warning

This is a legacy function, for security reasons do not use with rsa_pkcs1_padding. For digital signatures use of sign/3 together with verify/4 is the prefered solution.

encrypt_public(PlainText, Key)

(since OTP R14B)

-spec encrypt_public(PlainText, Key) -> CipherText
                        when PlainText :: binary(), Key :: rsa_public_key(), CipherText :: binary().

Equivalent to encrypt_public(PlainText, Key, []).

encrypt_public(PlainText, Key, Options)

(since OTP 21.1)

-spec encrypt_public(PlainText, Key, Options) -> CipherText
                        when
                            PlainText :: binary(),
                            Key :: rsa_public_key(),
                            Options :: crypto:pk_encrypt_decrypt_opts(),
                            CipherText :: binary().

Public-key encryption using the public key. See also crypto:public_encrypt/4.

Warning

This is a legacy function, for security reasons do not use with rsa_pkcs1_padding.

PEM API

pem_decode(PemBin)

(since OTP R14B)

-spec pem_decode(binary()) -> [pem_entry()].

Decodes PEM binary data and returns entries as ASN.1 DER encoded entities.

Example {ok, PemBin} = file:read_file("cert.pem"). PemEntries = public_key:pem_decode(PemBin).

pem_encode(PemEntries)

(since OTP R14B)

-spec pem_encode([pem_entry()]) -> binary().

Creates a PEM binary.

pem_entry_decode(PemEntry)

(since OTP R14B)

-spec pem_entry_decode(PemEntry) -> term() when PemEntry :: pem_entry().

Equivalent to pem_entry_decode(PemEntry, "").

pem_entry_decode(PemEntry, Password)

(since OTP R14B)

-spec pem_entry_decode(PemEntry, Password) -> term()
                          when PemEntry :: pem_entry(), Password :: iodata() | fun(() -> iodata()).

Decodes a PEM entry. pem_decode/1 returns a list of PEM entries. Notice that if the PEM entry is of type 'SubjectPublickeyInfo', it is further decoded to an rsa_public_key/0 or dsa_public_key/0.

Password can be either an octet string or function which returns same type.

pem_entry_encode(Asn1Type, Entity)

(since OTP R14B)

-spec pem_entry_encode(Asn1Type, Entity) -> pem_entry()
                          when Asn1Type :: pki_asn1_type(), Entity :: term().

Equivalent to pem_entry_encode/3.

pem_entry_encode(Asn1Type, Entity, InfoPwd)

(since OTP R14B)

-spec pem_entry_encode(Asn1Type, Entity, InfoPwd) -> pem_entry()
                          when
                              Asn1Type :: pki_asn1_type(),
                              Entity :: term(),
                              InfoPwd :: {CipherInfo, Password},
                              CipherInfo ::
                                  {Cipher :: iodata(),
                                   Salt ::
                                       binary() |
                                       {#'PBEParameter'{salt :: term(), iterationCount :: term()},
                                        digest_type()} |
                                       #'PBES2-params'{keyDerivationFunc :: term(),
                                                       encryptionScheme :: term()}},
                              Password :: iodata().

Creates a PEM entry that can be feed to pem_encode/1.

If Asn1Type is 'SubjectPublicKeyInfo', Entity must be either an rsa_public_key/0, dsa_public_key/0 or an ecdsa_public_key/0 and this function creates the appropriate 'SubjectPublicKeyInfo' entry.

Sign/Verify API

pkix_sign(Cert, Key)

(since OTP R14B)

-spec pkix_sign(Cert, Key) -> Der
                   when
                       Cert ::
                           #'OTPTBSCertificate'{version :: term(),
                                                serialNumber :: term(),
                                                signature :: term(),
                                                issuer :: term(),
                                                validity :: term(),
                                                subject :: term(),
                                                subjectPublicKeyInfo :: term(),
                                                issuerUniqueID :: term(),
                                                subjectUniqueID :: term(),
                                                extensions :: term()},
                       Key :: private_key(),
                       Der :: der_encoded().

Signs an 'OTPTBSCertificate'. Returns the corresponding DER-encoded certificate.

pkix_verify(Cert, Key)

(since OTP R14B)

-spec pkix_verify(Cert, Key) -> boolean() when Cert :: der_encoded(), Key :: public_key().

Verifies PKIX x.509 certificate signature.

sign(Msg, DigestType, Key)

-spec sign(Msg, DigestType, Key) -> Signature
              when
                  Msg :: binary() | {digest, binary()},
                  DigestType :: digest_type(),
                  Key :: private_key(),
                  Signature :: binary().

Equivalent to sign(Msg, DigestType, Key, []).

sign(Msg, DigestType, Key, Options)

(since OTP 20.1)

-spec sign(Msg, DigestType, Key, Options) -> Signature
              when
                  Msg :: binary() | {digest, binary()},
                  DigestType :: digest_type(),
                  Key :: private_key(),
                  Options :: crypto:pk_sign_verify_opts() | custom_key_opts(),
                  Signature :: binary().

Creates a digital signature.

The Msg is either the binary "plain text" data to be signed or it is the hashed value of "plain text", that is, the digest. The key can, besides a standard key, be a map specifing a key algorithm and a fun that should handle the signing. This may be used for customized signing with for instance hardware security modules (HSM) or trusted platform modules (TPM).

verify(Msg, DigestType, Signature, Key)

(since OTP R14B)

-spec verify(Msg, DigestType, Signature, Key) -> boolean()
                when
                    Msg :: binary() | {digest, binary()},
                    DigestType :: digest_type(),
                    Signature :: binary(),
                    Key :: public_key().

Equivalent to verify(Msg, DigestType, Signature, Key, []).

verify(Msg, DigestType, Signature, Key, Options)

(since OTP 20.1)

-spec verify(Msg, DigestType, Signature, Key, Options) -> boolean()
                when
                    Msg :: binary() | {digest, binary()},
                    DigestType :: digest_type(),
                    Signature :: binary(),
                    Key :: public_key(),
                    Options :: crypto:pk_sign_verify_opts().

Verifies a digital signature.

The Msg is either the binary "plain text" data or it is the hashed value of "plain text", that is, the digest.

Test Data API

pkix_test_data(ChainConf)

(since OTP 20.1)

-spec pkix_test_data(ChainConf) -> TestConf
                        when
                            ChainConf ::
                                #{server_chain := chain_opts(), client_chain := chain_opts()} |
                                chain_opts(),
                            TestConf ::
                                #{server_config := [conf_opt()], client_config := [conf_opt()]} |
                                [conf_opt()].

Creates certificate configuration(s) consisting of certificate and its private key plus CA certificate bundle, for a client and a server, intended to facilitate automated testing of applications using X509-certificates, often through SSL/TLS. The test data can be used when you have control over both the client and the server in a test scenario.

When this function is called with a map containing client and server chain specifications; it generates both a client and a server certificate chain where the cacerts returned for the server contains the root cert the server should trust and the intermediate certificates the server should present to connecting clients. The root cert the server should trust is the one used as root of the client certificate chain. Vice versa applies to the cacerts returned for the client. The root cert(s) can either be pre-generated with pkix_test_root_cert/2 , or if options are specified; it is (they are) generated.

When this function is called with a list of certificate options; it generates a configuration with just one node certificate where cacerts contains the root cert and the intermediate certs that should be presented to a peer. In this case the same root cert must be used for all peers. This is useful in for example an Erlang distributed cluster where any node, towards another node, acts either as a server or as a client depending on who connects to whom. The generated certificate contains a subject altname, which is not needed in a client certificate, but makes the certificate useful for both roles.

Explanation of the options used to customize certificates in the generated chains:

{digest, digest_type()} - Hash algorithm to be used for signing the certificate together with the key option. Defaults to sha that is sha1.

{key, ec_params()| {rsa, Size:pos_integer(), Prime::pos_integer()} | private_key()} - Parameters to be used to call public_key:generate_key/1, to generate a key, or an existing key. Defaults to generating an ECDSA key. Note this could fail if Erlang/OTP is compiled with a very old cryptolib.

{validity, {From::erlang:timestamp(), To::erlang:timestamp()}} - The validity period of the certificate.

{extensions, [#'Extension'{}]} - Extensions to include in the certificate.

Default extensions included in CA certificates if not otherwise specified are:

[#'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 function 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_test_root_cert(Name, Options)

(since OTP 20.2)

-spec pkix_test_root_cert(Name, Options) -> RootCertAndKey
                             when
                                 Name :: string(),
                                 Options :: [cert_opt()],
                                 RootCertAndKey :: #{cert := der_encoded(), key := private_key()}.

Generates a root certificate that can be used in multiple calls to pkix_test_data/1 when you want the same root certificate for several generated certificates.