tls: fix to handle X.509 v1 certificates correctly
authorIvan Abrea <ivan@algosolutions.com>
Sun, 24 Jun 2018 18:04:57 +0000 (20:04 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 24 Jun 2018 18:05:24 +0000 (20:05 +0200)
The syntax of public key certificates can be found in RFC 5280 section
4.1. The relevant part of the syntax is the following:

  TBSCertificate  ::=  SEQUENCE  {
    version         [0]  EXPLICIT Version DEFAULT v1,
    serialNumber         CertificateSerialNumber,
    ... remaining fields omitted ...
  }

The version field has a default value of v1. RFC 5280 section 4.1.2.1
says the following:

  If only basic fields are present, the version SHOULD be 1 (the value
  is omitted from the certificate as the default value); however, the
  version MAY be 2 or 3.

To help detect if the version field is present or not, the type of the
version field has an explicit tag of [0]. Due to this tag, if the
version field is present, its encoding will have an identifier octet
that is distinct from that of the serialNumber field.

ITU-T X.690 specifies how a value of such a type should be encoded with
DER. There is a PDF of X.690 freely available from ITU-T. X.690 section
8.1.2 specifies the format of identifier octets which is the first
component of every encoded value. Identifier octets encode the tag of a
type. Bits 8 and 7 encode the tag class. Bit 6 will be 0 if the encoding
is primitive and 1 if the encoding is constructed. Bits 5 to 1 encode
the tag number.

X.690 section 8.14 specifies what the identifier octet should be for
explicitly tagged types. Section 8.14.3 says if implicit tagging is not
used, then the encoding shall be constructed. The version field uses
explicit tagging and not implicit tagging, so its encoding will be
constructed. This means bit 6 of the identifier octet should be 1.

X.690 section 8.14 and Annex A provide examples. Note from their
examples that the notation for tags could look like [APPLICATION 2]
where both the tag class and tag number are given. For this example, the
tag class is 1 (application) and the tag number is 2. For notation like
[0] where the tag class is omitted and only the tag number is given, the
tag class will be context-specific.

Putting this all together, the identifier octet for the DER encoding of
the version field should have a tag class of 2 (context-specific), bit 6
as 1 (constructed), and a tag number of 0.

Signed-off-by: Ivan Abrea <ivan@algosolutions.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/tls.c

index 99722cfb427917f528b65017d28f626670b486dd..c8d9e9697f2365e8ea8860d05d1cbe69115e88ef 100644 (file)
@@ -1082,6 +1082,8 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len)
  * We need Certificate.tbsCertificate.subjectPublicKeyInfo.publicKey
  */
        uint8_t *end = der + len;
+       uint8_t tag_class, pc, tag_number;
+       int version_present;
 
        /* enter "Certificate" item: [der, end) will be only Cert */
        der = enter_der_item(der, &end);
@@ -1089,8 +1091,24 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len)
        /* enter "tbsCertificate" item: [der, end) will be only tbsCert */
        der = enter_der_item(der, &end);
 
+       /*
+        * Skip version field only if it is present. For a v1 certificate, the
+        * version field won't be present since v1 is the default value for the
+        * version field and fields with default values should be omitted (see
+        * RFC 5280 sections 4.1 and 4.1.2.1). If the version field is present
+        * it will have a tag class of 2 (context-specific), bit 6 as 1
+        * (constructed), and a tag number of 0 (see ITU-T X.690 sections 8.1.2
+        * and 8.14).
+        */
+       tag_class = der[0] >> 6; /* bits 8-7 */
+       pc = (der[0] & 32) >> 5; /* bit 6 */
+       tag_number = der[0] & 31; /* bits 5-1 */
+       version_present = tag_class == 2 && pc == 1 && tag_number == 0;
+       if (version_present) {
+               der = skip_der_item(der, end); /* version */
+       }
+
        /* skip up to subjectPublicKeyInfo */
-       der = skip_der_item(der, end); /* version */
        der = skip_der_item(der, end); /* serialNumber */
        der = skip_der_item(der, end); /* signatureAlgo */
        der = skip_der_item(der, end); /* issuer */