tor-browser

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

xbsconst.c (4815B)


      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 * X.509 v3 Basic Constraints Extension
      7 */
      8 
      9 #include "prtypes.h"
     10 #include <limits.h> /* for LONG_MAX */
     11 #include "seccomon.h"
     12 #include "secdert.h"
     13 #include "secoidt.h"
     14 #include "secasn1t.h"
     15 #include "secasn1.h"
     16 #include "certt.h"
     17 #include "secder.h"
     18 #include "prprf.h"
     19 #include "secerr.h"
     20 
     21 typedef struct EncodedContext {
     22    SECItem isCA;
     23    SECItem pathLenConstraint;
     24    SECItem encodedValue;
     25    PLArenaPool *arena;
     26 } EncodedContext;
     27 
     28 static const SEC_ASN1Template CERTBasicConstraintsTemplate[] = {
     29    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(EncodedContext) },
     30    { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */
     31      offsetof(EncodedContext, isCA) },
     32    { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER,
     33      offsetof(EncodedContext, pathLenConstraint) },
     34    { 0 }
     35 };
     36 
     37 static unsigned char hexTrue = 0xff;
     38 static unsigned char hexFalse = 0x00;
     39 
     40 #define GEN_BREAK(status) \
     41    rv = status;          \
     42    break;
     43 
     44 SECStatus
     45 CERT_EncodeBasicConstraintValue(PLArenaPool *arena, CERTBasicConstraints *value,
     46                                SECItem *encodedValue)
     47 {
     48    EncodedContext encodeContext;
     49    PLArenaPool *our_pool = NULL;
     50    SECStatus rv = SECSuccess;
     51 
     52    do {
     53        PORT_Memset(&encodeContext, 0, sizeof(encodeContext));
     54        if (!value->isCA && value->pathLenConstraint >= 0) {
     55            PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);
     56            GEN_BREAK(SECFailure);
     57        }
     58 
     59        encodeContext.arena = arena;
     60        if (value->isCA == PR_TRUE) {
     61            encodeContext.isCA.data = &hexTrue;
     62            encodeContext.isCA.len = 1;
     63        }
     64 
     65        /* If the pathLenConstraint is less than 0, then it should be
     66         * omitted from the encoding.
     67         */
     68        if (value->isCA && value->pathLenConstraint >= 0) {
     69            our_pool = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
     70            if (our_pool == NULL) {
     71                PORT_SetError(SEC_ERROR_NO_MEMORY);
     72                GEN_BREAK(SECFailure);
     73            }
     74            if (SEC_ASN1EncodeUnsignedInteger(
     75                    our_pool, &encodeContext.pathLenConstraint,
     76                    (unsigned long)value->pathLenConstraint) == NULL) {
     77                PORT_SetError(SEC_ERROR_NO_MEMORY);
     78                GEN_BREAK(SECFailure);
     79            }
     80        }
     81        if (SEC_ASN1EncodeItem(arena, encodedValue, &encodeContext,
     82                               CERTBasicConstraintsTemplate) == NULL) {
     83            GEN_BREAK(SECFailure);
     84        }
     85    } while (0);
     86    if (our_pool)
     87        PORT_FreeArena(our_pool, PR_FALSE);
     88    return (rv);
     89 }
     90 
     91 SECStatus
     92 CERT_DecodeBasicConstraintValue(CERTBasicConstraints *value,
     93                                const SECItem *encodedValue)
     94 {
     95    EncodedContext decodeContext;
     96    PORTCheapArenaPool tmpArena;
     97    SECStatus rv = SECSuccess;
     98 
     99    do {
    100        PORT_Memset(&decodeContext, 0, sizeof(decodeContext));
    101        /* initialize the value just in case we got "0x30 00", or when the
    102           pathLenConstraint is omitted.
    103         */
    104        decodeContext.isCA.data = &hexFalse;
    105        decodeContext.isCA.len = 1;
    106 
    107        PORT_InitCheapArena(&tmpArena, SEC_ASN1_DEFAULT_ARENA_SIZE);
    108 
    109        rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &decodeContext,
    110                                    CERTBasicConstraintsTemplate, encodedValue);
    111        if (rv == SECFailure)
    112            break;
    113 
    114        value->isCA = decodeContext.isCA.data
    115                          ? (PRBool)(decodeContext.isCA.data[0] != 0)
    116                          : PR_FALSE;
    117        if (decodeContext.pathLenConstraint.data == NULL) {
    118            /* if the pathLenConstraint is not encoded, and the current setting
    119              is CA, then the pathLenConstraint should be set to a negative
    120              number
    121              for unlimited certificate path.
    122             */
    123            if (value->isCA) {
    124                value->pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
    125            } else {
    126                value->pathLenConstraint = 0;
    127            }
    128        } else if (value->isCA) {
    129            long len = DER_GetInteger(&decodeContext.pathLenConstraint);
    130            if (len < 0 || len == LONG_MAX) {
    131                PORT_SetError(SEC_ERROR_BAD_DER);
    132                GEN_BREAK(SECFailure);
    133            }
    134            value->pathLenConstraint = len;
    135        } else {
    136            /* here we get an error where the subject is not a CA, but
    137               the pathLenConstraint is set */
    138            PORT_SetError(SEC_ERROR_BAD_DER);
    139            GEN_BREAK(SECFailure);
    140            break;
    141        }
    142    } while (0);
    143 
    144    PORT_DestroyCheapArena(&tmpArena);
    145    return (rv);
    146 }