From: Ivan Abrea Date: Sun, 24 Jun 2018 18:04:57 +0000 (+0200) Subject: tls: fix to handle X.509 v1 certificates correctly X-Git-Tag: 1_29_0~24 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=5cb4f9081f3f6575da052b03cb227a7a488b0a8b;p=oweals%2Fbusybox.git tls: fix to handle X.509 v1 certificates correctly 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 Signed-off-by: Denys Vlasenko --- diff --git a/networking/tls.c b/networking/tls.c index 99722cfb4..c8d9e9697 100644 --- a/networking/tls.c +++ b/networking/tls.c @@ -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 */