Subject: OpenPGP Signatures Incorporating X.509 Certificates

From: [email-masked] ("Hal Finney")
Date: Tue, 12 Apr 2005 14:58:27 -0700 (PDT)

OpenPGP Signatures Incorporating X.509 Certificates

        Copyright 2005 by PGP Corporation. All Rights Reserved.

Abstract

   This document is published to document the procedure used by
   commercial PGP [PGP] products up through version 9 for incorporating
   X.509 [X.509-00] certificates into OpenPGP [RFC2440] format
   signatures, and for cryptographically validating such signatures.  It
   describes only the format and methods needed to import X.509
   certificates, and to validate key signature packets containing such
   certificates.  It does not deal with storage and implementation
   questions.

1. Introduction

   The OpenPGP [RFC2440] specification describes data formats for
   representing public keys, userids, and key signatures that
   cryptographically bind keys, userids, and fields from signature
   packets.  It further describes the cryptographic procedures used to
   sign and verify the signature packets which comply with that
   specification.

   An alternative set of standards and formats is widely used in network
   applications for communicating cryptographic bindings of public keys
   and associated name data, based on the X.509 [X.509-00] certificate
   format.  X.509 certificates communicate similar information to
   OpenPGP key, userid and signature packets.  However, the details of
   the data formats are incompatible and it is not possible to transform
   X.509 certificates into sequences of OpenPGP packets that can be
   cryptographically validated by the mechanisms described in RFC2440.

   This document presents an alternative mechanism to allow X.509
   certificates to be imported into OpenPGP data formats and
   cryptographically validated.  It describes both the detailed data
   formats used to import and represent X.509 data in OpenPGP packets,
   and the procedures necessary to cryptographically validate such X.509
   based OpenPGP signatures.  These mechanisms allow the cryptographic
   infrastructure based on X.509 certificates to be imported and used in
   the context of OpenPGP messages and data.

1.1. Overview of Importing Certificates

   X.509 certificates are imported into OpenPGP signature packets in
   three steps, which will be described in more detail in section 2.

                                                                [Page 1]

                                   -2-

   First, the numeric key material (the RSA modulus and exponent, and
   corresponding values for other key types) is used to construct an
   OpenPGP key packet.  Second, the name field(s) of the X.509
   certificate are used to construct an OpenPGP userid packet.  And
   third, an OpenPGP signature packet is constructed from the
   certificate.  Some fields of the OpenPGP signature packet are set
   from corresponding fields in the certificate.  In addition, the
   certificate itself is inserted as a whole into the OpenPGP signature
   packet, in a signature subpacket.

   During the import process, the keyring is searched for a pre-existing
   OpenPGP key which matches the numeric key material being imported.
   If so, the userid and signature are added to the existing key.  This
   also requires checking to see whether there is already a userid on
   the key matching the userid constructed by the import process; if so,
   the new signature packet is added to the pre-existing userid.  This
   allows OpenPGP keys to hold a combination of X.509 based signatures
   and regular OpenPGP signatures.

   Once the X.509 certificate has been imported, the resulting OpenPGP
   keys and userids can be used interchangeably with regular OpenPGP
   keys.  The only difference is in the format of the X.509 signatures.

1.2. Validating Certificates

   Cryptographically validating an X.509 signature packet requires a
   special process.  It is not possible to use the normal OpenPGP
   signature validation process because no cryptographically valid
   signature exists over the OpenPGP data.  Instead, a two step process
   is used.

   First, the X.509 certificate is tested for consistency with the
   OpenPGP packets.  This requires extracting the X.509 certificate from
   the OpenPGP signature packet.  It is then put through a process
   similar to when it was first imported into the OpenPGP format per
   this specification, to create temporary OpenPGP key, userid and
   signature packets from the certificate data.  These temporary packets
   are compared with the OpenPGP key, userid and signature packets from
   the OpenPGP key holding the X.509 certificate signature.  There must
   be an exact, byte-for-byte match between the two sets of packets for
   this step of the validation to be considered successful.  This
   guarantees that the material in the OpenPGP packets is consistent
   with the contents of the X.509 certificate.

   Second, the X.509 certificate is itself cryptographically validated.
   This is a straightforward matter of computing the hash over the "to
   be signed" portion of the certificate and running the cryptographic
   signature verification algorithm using that hash and using the

                                                                [Page 2]

                                   -3-

   signature field of the certificate.  This step requires that the
   cryptographic key material of the issuing certificate must be
   present; for example, it may be available on the keyring as an
   OpenPGP key if it was previously imported into the OpenPGP format.

   Together, these two steps assure that the issuing key issued the
   certificate, and that the resulting OpenPGP key, userid and signature
   packets faithfully reflect the information put into the certificate
   by the issuer.  On this basis the X.509 certificate signature is
   considered to be valid.

1.3. Identifying Signing Keys

   The OpenPGP specification uses keyids to link signatures to the keys
   which issued them.  X.509 uses a different method, based on the
   issuer name.  As a result, X.509 signature packets do not have keyid
   subpackets.  Instead, to find the key which issued an X.509 signature
   packet it is necessary to extract the X.509 certificate, parse it to
   extract the issuer field, and then to search the other X.509
   signature packets on the keyring for an X.509 certificate whose
   subject name matches.  The key to which that certificate signature is
   attached is the one which issued the X.509 signature being validated.

2. Importing X.509 Certificates

   Note that the rules and procedures below for importing an X.509
   certificate must be followed precisely by any compatible
   implementation.  This is because checking the cryptographic validity
   of an X.509 signature requires extracting the certificate from the
   X.509 signature and repeating the import process, comparing the
   results byte for byte with the OpenPGP key, userid and signature
   packets.  Any variation between implementations, even seemingly
   inconsequential ones like changing the order of various subpackets or
   userid fields, will cause this bytewise comparison to fail and cause
   the signature to be treated as invalid.

2.1. Creating the Key Packet

   The first step in importing an X.509 certificate into OpenPGP is to
   create an OpenPGP key packet which includes the numeric key material
   from the certificate.  X.509 certificates holding RSA, DSS or ElGamal
   keys may be imported.  The data is extracted from the
   SubjectPublicKeyInfo field of the certificate and converted into
   OpenPGP public key format.

   OpenPGP public key packets contain four additional pieces of
   information.  First, they have a version number.  Version 3 and 4
   packets are presently in use.  Second, they have a creation date

                                                                [Page 3]

                                   -4-

   field.  Third, version 3 packets have a field encoding the duration
   until key expiration.  And fourth, they hold an algorithm identifier
   for the public key algorithm the key represents.

   In importing the key, the keyring should be searched for an existing
   key whose numeric key material matches that of the certificate being
   imported.  If a match is found, that key packet is used as the basis
   for filling in these other fields.  This uses the version number,
   creation date and expiration period fields from the pre-existing key.

   If no matching key exists, the new OpenPGP packet is created with
   version 4, and the public key algorithm field is set from the type of
   public key in the X.509 certificate.  V4 keys do not have expiration
   periods, so that leaves only the creation date.

   X.509 certificates normally do not specify a key creation date, only
   a certificate creation date.  A somewhat complicated mechanism is
   available to facilitate setting a reliable key creation date field in
   the OpenPGP public key packet.

   This mechanism is intended to facilitate allowing pre-existing
   OpenPGP keys to acquire X.509 certificates on their key material.
   These X.509 certificates could then be distributed and imported into
   other users' OpenPGP compatible software.  In order to keep the
   resulting OpenPGP keys compatible with the ones which were certified,
   OpenPGP encodes the key creation date into the X.509 certificate
   request which is sent to be certified.  With a cooperative
   certificate issuing authority (CA), the key creation date is then
   embedded in the certificate in a special format.  This ensures that
   when other users import the X.509 certificate, they will create the
   OpenPGP key with the same creation date that the original key had.

   This is especially important in case the importing user did not
   previously have a copy of the original OpenPGP key, but acquired it
   by importing the X.509 certificate; and then he later imports the
   original OpenPGP key as a conventional-format OpenPGP key, rather
   than as a certificate.  Without the special mechanism for handling
   creation dates, the creation dates wouldn't match, and the keyids of
   the two keys would be different, making them appear to be two
   different keys.  Putting the key creation date into the X.509
   certificate helps to insure that importing the certificate will
   correctly reconstruct the OpenPGP key.

   Two alternative mechanisms are available for encoding this
   information into the X.509 certificate.  The preferred mechanism is a
   custom extension created for this purpose.  The OID for this
   extension is (1 3 6 1 4 1 3401 8 1 1), encoded as the octet string
   {0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x9a, 0x49, 0x08, 0x01,

                                                                [Page 4]

                                   -5-

   0x01}.  The data for the extension is defined as:

   PGPExtension ::= SEQUENCE {
        version             Version DEFAULT v1,
        keyCreation         Time
   }

   The OpenPGP key creation data is stored in X.509 Time format, the
   same format used for the notBefore and notAfter subfields of the
   certificate validity field.  This is converted to the four byte
   OpenPGP time format specified in RFC2440 and used as the key creation
   field in the new OpenPGP key packet.

   The second method for encoding the OpenPGP creation date into an
   X.509 certificate is used if the custom extension is not supported by
   the CA.  It stores the OpenPGP creation date in a field in the
   subject Distinguished Name.  It uses either an Organizational Unit or
   Description field in the subject name.  The creation date is stored
   in one of these field types, with associated data in the format
   "PGPKeyCreation=0x........" where the dots are replaced by 8 hex
   digits that encode the creation date in OpenPGP time format.  If such
   a field is found, the hex value after "0x" is converted to binary
   data and used as the creation date in the OpenPGP key packet.

   On import, the certificate is searched sequentially for these two
   possible encodings of creation date.  The first match is used,
   although typically there would not be more than one such encoding
   present in a certificate.  Because subject name comes before
   extensions, the subject name fields are checked first, then the
   extensions.

   If none of these methods work to find an OpenPGP creation date, as
   will typically be the case on a certificate which was created via
   X.509 mechanisms and not by certifying an OpenPGP key, the
   certificate notBefore field is converted to OpenPGP time format and
   used as the key creation date.

2.2. Creating the UserID Packet

   Two alternative methods are available to create an OpenPGP UserID
   packet from an X.509 certificate, the short name format and the long
   name format.  The short name format is used if the conditions
   described below are met, otherwise the long name format is used.

   The short name format for the userid is of the form "common_name
   <email_address>", a widely used format for OpenPGP userids.  For this
   format to be used it must be possible to extract a common name and
   email address from the certificate.  The common name must come from

                                                                [Page 5]

                                   -6-

   the subject name field.  The email address may come from either the
   subject name, where its OID is (1 2 840 113549 1 9 1), or from a
   SubjectAlternativeName field in an extension, where the choice type
   is rfc822Name.

   As a special case, the short name format is also used if the subject
   name has only a single field, which is an email address, but there is
   no common name.  In that case the userid is created as
   "<email_address>".

   If it is not possible to satisfy these conditions for creating the
   userid in the short format, a long format is used.  This is a slight
   modification of "Lightweight Directory Access Protocol (v3): UTF-8
   String Representation of Distinguished Names" [RFC2253], applied to
   the subject name field of the certificate.

   RFC2253 puts the DN fields into reverse order, but this specification
   modifies that rule somewhat.  The common name field (if present) is
   always output first, before the other fields, to improve readability.
   Also, any name field corresponding to the special OpenPGP key
   creation date field described in the section 2.1, if present, is
   skipped and is not output.

   The only DN field names which get converted into printable form for
   the userid are CN, C, L, ST, STREET, O, OU and EMAIL.  Other fields
   in the DN are ignored when converting to an OpenPGP userid.  Note
   that any SubjectAlternativeName extensions are not used when
   outputting a long format name.  Only the fields from the subject name
   of the certificate are put into the OpenPGP userid packet.

   If no fields from the list above are found in the DN, the userid
   packet is created with the text "(Unknown X509 name)".

2.3. Creating the Signature Packet

   Creating the OpenPGP signature packet from an X.509 certificate
   involves two steps.  The first is to include the certificate itself,
   in total, into a new subpacket of the OpenPGP signature packet.  The
   second is to set up the various signature packet fields and
   subpackets which encode the supported semantics of the X.509
   certificate.

2.3.1. X.509 Signature Subpacket Format

   This specification defines a new OpenPGP subpacket type.  It uses
   subpacket type 100, defined in RFC2440 as within the private range of
   subpackets.  The first byte of the subpacket is 1, indicating that
   the type of the private-range subpacket is an X.509 certificate.  The

                                                                [Page 6]

                                   -7-

   next two bytes are major and minor version numbers.  The major
   version is 1 for all compatible implementations of this
   specification.  The minor version reflects changes in the detailed
   rules for how X.509 certificates are converted to OpenPGP keys.  The
   current minor version is 4, and this value should be used in newly
   created certificate subpackets.

   When verifying an X.509 certificate signature, the minor version
   number must be parsed and used to guide the conversion process.
   Since part of the verification involves checking for consistency
   between the X.509 certificate and the OpenPGP packets, any
   differences would cause the signature to be treated as invalid.  When
   changes are made for how this conversion is done, the minor version
   must be upgraded.

   The only operational difference at this point is between minor
   version 4 vs. earlier minor version numbers of 3 or less.  There is a
   change to the public key algorithm field used in the signature
   packet, as described below.  No other changes presently exist based
   on minor version number, for importing signature, userid or key
   packets.

   The remaining data in the certificate subpacket is the X.509
   certificate itself.  Its length is determined implicitly by the
   subpacket length minus the fields already described.  X.509
   certificates are self-delimiting, and the certificate must end at the
   end of the data range in the subpacket allocated to hold it.

2.3.2. Other Signature Fields

   In addition to inserting the certificate bodily into a new subpacket,
   other fields of the OpenPGP signature packet are created to be
   consistent with the data from the certificate.  Note that it is
   necessary to follow the description in this section precisely in
   order to create X.509 signature packets which will interoperate with
   other software implementing this specification.  No flexibility is
   possible in the set of signature packets created, the contents of the
   packet, or the ordering of the packets.  This consistency is
   necessary in order for the byte-for-byte packet comparison to succeed
   when signatures are verified.

   OpenPGP signature packets created from X.509 certificates are version
   4 packets.  The signature type field is 0x10, "generic certification
   of a user id and public key packet".  The next field is the public
   key algorithm, which guides the signature verification process.  As
   described in the introduction, X.509 signature packets cannot be
   cryptographically verified by the normal OpenPGP verification rules.
   To flag this fact and make sure an OpenPGP implementation of this

                                                                [Page 7]

                                   -8-

   specification does not try to verify the packet, a reserved value is
   used for the public key algorithm field.

   This is the one place the minor version number from the certificate
   subpacket is used.  For minor versions 0-3, the reserved value is 0.
   For minor version 4, the reserved value is 100, which is in the
   reserved range for RFC2440.  In either case, it is meant to indicate
   that the regular OpenPGP certificate verification process will not
   work, and to prevent noncompliant OpenPGP implementations from
   attempting to verify signatures created by this specification.

   The next field in the V4 signature packet is the hash algorithm ID,
   which is set to the hash algorithm from the X.509 certificate.  If a
   certificate uses a public key or hash algorithm not recognized by
   RFC2440, it is not allowed to be imported per this specification.

   The next part of the signature packet contains the so-called hashed
   subpackets.  Note that these subpackets are not actually hashed, in
   an X.509 signature packet; rather, their validity is verified based
   on comparison with the X.509 certificate, which does get
   cryptographically hashed and verified.  Several such subpackets are
   created, based on X.509 certificate data.  The order of these
   subpackets is significant in that the certificate verification
   process described in section 1.2 will attempt to re-convert the X.509
   certificate into an OpenPGP signature packet and do a byte-for-byte
   match between the re-converted data and the original signature data.
   The packets must be identical for the X.509 signature to be
   considered valid.

   The first subpacket is signature creation time, subpacket ID 2.  This
   is taken from the notBefore subfield of the validity field in the
   certificate, and converted to OpenPGP time format.

   The second subpacket is signature expiration time, subpacket ID 3.
   This is taken from the notAfter subfield of the validity field in the
   certificate, and converted to OpenPGP time format.  The signature
   creation time is then subtracted, because OpenPGP actually stores the
   signature validity duration in seconds in the expiration time
   subpacket.

   Next is an optional trust signature subpacket, ID 5.  It is used if
   the imported certificate has a BasicConstraints extension with the
   boolean cA field being true, representing a CA certificate.  The
   trust signature subpacket holds two bytes. The first is the trust
   "level", which means the depth to which trust is delegated.  This is
   set based on any PathLenConstraint field of the BasicConstraints
   extension.  If there is no PathLenConstraint, the level value stored
   in the trust packet is the maximum value of 255.  If there is a

                                                                [Page 8]

                                   -9-

   PathLenConstraint value in the certificate, the trust level stored is
   equal to that integer value, plus one (then truncated to one byte).
   The trust packet also has a second byte representing the validity of
   the trust being extended, which is set to 120, meaning complete
   validity.

   Next there is an optional a key flags subpacket, ID 27.  It is used
   if there is a KeyUsage extension in the imported certificate, to
   encode any key usage restrictions.  Not all bits in the KeyUsage
   extension are recognized and converted by this specification, but the
   key flags subpacket is created even if none of the bits are
   recognized, in which case the key flags subpacket will be output with
   a flag value of zero.  The bits which are recognized, and the
   corresponding OpenPGP key flags values, are as follows:

   keyCertSign      ---> flag 0x01, key can certify other keys
   cRLSign          ---> flag 0x01, key can certify other keys
   digitalSignature ---> flag 0x02, key can sign data
   nonRepudiation   ---> flag 0x02, key can sign data
   keyEncipherment  ---> flags 0x14, key can encrypt communications
                         and key can encrypt storage
   dataEncipherment ---> flags 0x14, key can encrypt communications
                         and key can encrypt storage
   keyAgreement     ---> flags 0x14, key can encrypt communications
                         and key can encrypt storage

   All other key flag bits in the four byte field are output as zero.

   The last subpacket output is the X.509 certificate subpacket, ID 100,
   as described in section 2.3.1. above.

   Following the hashed data subpackets in the signature packet are the
   unhashed packets.  No such packets are used when importing an X.509
   signature, so the length of the unhashed region must be zero.  Note
   in particular that X.509 signature packets do not have an issuing
   keyid field.  This is because X.509 certificates refer to their
   issuer by name, rather than by keyid, as discussed in section 1.3.

   Next comes a two byte checksum, which is set to two bytes of zero.
   Finally there is the MPI data for the OpenPGP signature.  No MPI data
   is used for signatures in this specification, so a dummy MPI value of
   1 is stored, represented as the three byte sequence 0, 1, 1.  That
   ends the OpenPGP signature packet.

                                                                [Page 9]

                                  -10-

3. References

   [PGP]       PGP Corporation, http://www.pgp.com.

   [RFC2253]   M. Wahl, S. Kille, T. Howes, "Lightweight Directory
   Access Protocol (v3): UTF-8 String Representation of Distinguished
   Names", RFC 2253, December, 1997.

   [RFC2440]   J. Callas, L. Donnerhacke, H. Finney, R. Thayer, "OpenPGP
   Message Format", RFC 2440, November, 1998.

   [X.509-00]  ITU-T.  Recommendation X.509: The Directory -
   Authentication Framework.  2000.

                                                               [Page 10]