tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

certv3.c (5737B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /*
      6 * Code for dealing with X509.V3 extensions.
      7 */
      8 
      9 #include "cert.h"
     10 #include "secitem.h"
     11 #include "secoid.h"
     12 #include "secder.h"
     13 #include "secasn1.h"
     14 #include "certxutl.h"
     15 #include "secerr.h"
     16 
     17 SECStatus
     18 CERT_FindCertExtensionByOID(CERTCertificate *cert, SECItem *oid, SECItem *value)
     19 {
     20    return (cert_FindExtensionByOID(cert->extensions, oid, value));
     21 }
     22 
     23 SECStatus
     24 CERT_FindCertExtension(const CERTCertificate *cert, int tag, SECItem *value)
     25 {
     26    return (cert_FindExtension(cert->extensions, tag, value));
     27 }
     28 
     29 static void
     30 SetExts(void *object, CERTCertExtension **exts)
     31 {
     32    CERTCertificate *cert = (CERTCertificate *)object;
     33 
     34    cert->extensions = exts;
     35    DER_SetUInteger(cert->arena, &(cert->version), SEC_CERTIFICATE_VERSION_3);
     36 }
     37 
     38 void *
     39 CERT_StartCertExtensions(CERTCertificate *cert)
     40 {
     41    return (cert_StartExtensions((void *)cert, cert->arena, SetExts));
     42 }
     43 
     44 /*
     45 * get the value of the Netscape Certificate Type Extension
     46 */
     47 SECStatus
     48 CERT_FindNSCertTypeExtension(CERTCertificate *cert, SECItem *retItem)
     49 {
     50 
     51    return (CERT_FindBitStringExtension(
     52        cert->extensions, SEC_OID_NS_CERT_EXT_CERT_TYPE, retItem));
     53 }
     54 
     55 /*
     56 * get the value of a string type extension
     57 */
     58 char *
     59 CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag)
     60 {
     61    SECItem wrapperItem, tmpItem = { siBuffer, 0 };
     62    SECStatus rv;
     63    PLArenaPool *arena = NULL;
     64    char *retstring = NULL;
     65 
     66    wrapperItem.data = NULL;
     67    tmpItem.data = NULL;
     68 
     69    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     70 
     71    if (!arena) {
     72        goto loser;
     73    }
     74 
     75    rv = cert_FindExtension(cert->extensions, oidtag, &wrapperItem);
     76    if (rv != SECSuccess) {
     77        goto loser;
     78    }
     79 
     80    rv = SEC_QuickDERDecodeItem(
     81        arena, &tmpItem, SEC_ASN1_GET(SEC_IA5StringTemplate), &wrapperItem);
     82 
     83    if (rv != SECSuccess) {
     84        goto loser;
     85    }
     86 
     87    retstring = (char *)PORT_Alloc(tmpItem.len + 1);
     88    if (retstring == NULL) {
     89        goto loser;
     90    }
     91 
     92    PORT_Memcpy(retstring, tmpItem.data, tmpItem.len);
     93    retstring[tmpItem.len] = '\0';
     94 
     95 loser:
     96    if (arena) {
     97        PORT_FreeArena(arena, PR_FALSE);
     98    }
     99 
    100    if (wrapperItem.data) {
    101        PORT_Free(wrapperItem.data);
    102    }
    103 
    104    return (retstring);
    105 }
    106 
    107 /*
    108 * get the value of the X.509 v3 Key Usage Extension
    109 */
    110 SECStatus
    111 CERT_FindKeyUsageExtension(CERTCertificate *cert, SECItem *retItem)
    112 {
    113 
    114    return (CERT_FindBitStringExtension(cert->extensions,
    115                                        SEC_OID_X509_KEY_USAGE, retItem));
    116 }
    117 
    118 /*
    119 * get the value of the X.509 v3 Key Usage Extension
    120 */
    121 SECStatus
    122 CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem)
    123 {
    124 
    125    SECStatus rv;
    126    SECItem encodedValue = { siBuffer, NULL, 0 };
    127    SECItem decodedValue = { siBuffer, NULL, 0 };
    128 
    129    rv = cert_FindExtension(cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID,
    130                            &encodedValue);
    131    if (rv == SECSuccess) {
    132        PORTCheapArenaPool tmpArena;
    133        PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
    134        rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &decodedValue,
    135                                    SEC_ASN1_GET(SEC_OctetStringTemplate),
    136                                    &encodedValue);
    137        if (rv == SECSuccess) {
    138            rv = SECITEM_CopyItem(NULL, retItem, &decodedValue);
    139        }
    140        PORT_DestroyCheapArena(&tmpArena);
    141    }
    142    SECITEM_FreeItem(&encodedValue, PR_FALSE);
    143    return rv;
    144 }
    145 
    146 SECStatus
    147 CERT_FindBasicConstraintExten(CERTCertificate *cert,
    148                              CERTBasicConstraints *value)
    149 {
    150    SECItem encodedExtenValue;
    151    SECStatus rv;
    152 
    153    encodedExtenValue.data = NULL;
    154    encodedExtenValue.len = 0;
    155 
    156    rv = cert_FindExtension(cert->extensions, SEC_OID_X509_BASIC_CONSTRAINTS,
    157                            &encodedExtenValue);
    158    if (rv != SECSuccess) {
    159        return (rv);
    160    }
    161 
    162    rv = CERT_DecodeBasicConstraintValue(value, &encodedExtenValue);
    163 
    164    /* free the raw extension data */
    165    PORT_Free(encodedExtenValue.data);
    166    encodedExtenValue.data = NULL;
    167 
    168    return (rv);
    169 }
    170 
    171 CERTAuthKeyID *
    172 CERT_FindAuthKeyIDExten(PLArenaPool *arena, CERTCertificate *cert)
    173 {
    174    SECItem encodedExtenValue;
    175    SECStatus rv;
    176    CERTAuthKeyID *ret;
    177 
    178    encodedExtenValue.data = NULL;
    179    encodedExtenValue.len = 0;
    180 
    181    rv = cert_FindExtension(cert->extensions, SEC_OID_X509_AUTH_KEY_ID,
    182                            &encodedExtenValue);
    183    if (rv != SECSuccess) {
    184        return (NULL);
    185    }
    186 
    187    ret = CERT_DecodeAuthKeyID(arena, &encodedExtenValue);
    188 
    189    PORT_Free(encodedExtenValue.data);
    190    encodedExtenValue.data = NULL;
    191 
    192    return (ret);
    193 }
    194 
    195 SECStatus
    196 CERT_CheckCertUsage(CERTCertificate *cert, unsigned char usage)
    197 {
    198    SECItem keyUsage;
    199    SECStatus rv;
    200 
    201    /* There is no extension, v1 or v2 certificate */
    202    if (cert->extensions == NULL) {
    203        return (SECSuccess);
    204    }
    205 
    206    keyUsage.data = NULL;
    207 
    208    /* This code formerly ignored the Key Usage extension if it was
    209    ** marked non-critical.  That was wrong.  Since we do understand it,
    210    ** we are obligated to honor it, whether or not it is critical.
    211    */
    212    rv = CERT_FindKeyUsageExtension(cert, &keyUsage);
    213    if (rv == SECFailure) {
    214        rv = (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) ? SECSuccess
    215                                                                : SECFailure;
    216    } else if (!keyUsage.data || !keyUsage.len || !(keyUsage.data[0] & usage)) {
    217        PORT_SetError(SEC_ERROR_CERT_USAGES_INVALID);
    218        rv = SECFailure;
    219    }
    220    PORT_Free(keyUsage.data);
    221    return (rv);
    222 }