andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: /* andre@0: * X.509 v3 Basic Constraints Extension andre@0: */ andre@0: andre@0: #include "prtypes.h" andre@0: #include /* for LONG_MAX */ andre@0: #include "seccomon.h" andre@0: #include "secdert.h" andre@0: #include "secoidt.h" andre@0: #include "secasn1t.h" andre@0: #include "secasn1.h" andre@0: #include "certt.h" andre@0: #include "secder.h" andre@0: #include "prprf.h" andre@0: #include "secerr.h" andre@0: andre@0: typedef struct EncodedContext{ andre@0: SECItem isCA; andre@0: SECItem pathLenConstraint; andre@0: SECItem encodedValue; andre@0: PLArenaPool *arena; andre@0: }EncodedContext; andre@0: andre@0: static const SEC_ASN1Template CERTBasicConstraintsTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, andre@0: 0, NULL, sizeof(EncodedContext) }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */ andre@0: offsetof(EncodedContext,isCA)}, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER, andre@0: offsetof(EncodedContext,pathLenConstraint) }, andre@0: { 0, } andre@0: }; andre@0: andre@0: static unsigned char hexTrue = 0xff; andre@0: static unsigned char hexFalse = 0x00; andre@0: andre@0: #define GEN_BREAK(status) rv = status; break; andre@0: andre@0: SECStatus CERT_EncodeBasicConstraintValue andre@0: (PLArenaPool *arena, CERTBasicConstraints *value, SECItem *encodedValue) andre@0: { andre@0: EncodedContext encodeContext; andre@0: PLArenaPool *our_pool = NULL; andre@0: SECStatus rv = SECSuccess; andre@0: andre@0: do { andre@0: PORT_Memset (&encodeContext, 0, sizeof (encodeContext)); andre@0: if (!value->isCA && value->pathLenConstraint >= 0) { andre@0: PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); andre@0: GEN_BREAK (SECFailure); andre@0: } andre@0: andre@0: encodeContext.arena = arena; andre@0: if (value->isCA == PR_TRUE) { andre@0: encodeContext.isCA.data = &hexTrue ; andre@0: encodeContext.isCA.len = 1; andre@0: } andre@0: andre@0: /* If the pathLenConstraint is less than 0, then it should be andre@0: * omitted from the encoding. andre@0: */ andre@0: if (value->isCA && value->pathLenConstraint >= 0) { andre@0: our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); andre@0: if (our_pool == NULL) { andre@0: PORT_SetError (SEC_ERROR_NO_MEMORY); andre@0: GEN_BREAK (SECFailure); andre@0: } andre@0: if (SEC_ASN1EncodeUnsignedInteger andre@0: (our_pool, &encodeContext.pathLenConstraint, andre@0: (unsigned long)value->pathLenConstraint) == NULL) { andre@0: PORT_SetError (SEC_ERROR_NO_MEMORY); andre@0: GEN_BREAK (SECFailure); andre@0: } andre@0: } andre@0: if (SEC_ASN1EncodeItem (arena, encodedValue, &encodeContext, andre@0: CERTBasicConstraintsTemplate) == NULL) { andre@0: GEN_BREAK (SECFailure); andre@0: } andre@0: } while (0); andre@0: if (our_pool) andre@0: PORT_FreeArena (our_pool, PR_FALSE); andre@0: return(rv); andre@0: andre@0: } andre@0: andre@0: SECStatus CERT_DecodeBasicConstraintValue andre@0: (CERTBasicConstraints *value, const SECItem *encodedValue) andre@0: { andre@0: EncodedContext decodeContext; andre@0: PLArenaPool *our_pool; andre@0: SECStatus rv = SECSuccess; andre@0: andre@0: do { andre@0: PORT_Memset (&decodeContext, 0, sizeof (decodeContext)); andre@0: /* initialize the value just in case we got "0x30 00", or when the andre@0: pathLenConstraint is omitted. andre@0: */ andre@0: decodeContext.isCA.data =&hexFalse; andre@0: decodeContext.isCA.len = 1; andre@0: andre@0: our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); andre@0: if (our_pool == NULL) { andre@0: PORT_SetError (SEC_ERROR_NO_MEMORY); andre@0: GEN_BREAK (SECFailure); andre@0: } andre@0: andre@0: rv = SEC_QuickDERDecodeItem andre@0: (our_pool, &decodeContext, CERTBasicConstraintsTemplate, encodedValue); andre@0: if (rv == SECFailure) andre@0: break; andre@0: andre@0: value->isCA = decodeContext.isCA.data andre@0: ? (PRBool)(decodeContext.isCA.data[0] != 0) andre@0: : PR_FALSE; andre@0: if (decodeContext.pathLenConstraint.data == NULL) { andre@0: /* if the pathLenConstraint is not encoded, and the current setting andre@0: is CA, then the pathLenConstraint should be set to a negative number andre@0: for unlimited certificate path. andre@0: */ andre@0: if (value->isCA) andre@0: value->pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; andre@0: } else if (value->isCA) { andre@0: long len = DER_GetInteger (&decodeContext.pathLenConstraint); andre@0: if (len < 0 || len == LONG_MAX) { andre@0: PORT_SetError (SEC_ERROR_BAD_DER); andre@0: GEN_BREAK (SECFailure); andre@0: } andre@0: value->pathLenConstraint = len; andre@0: } else { andre@0: /* here we get an error where the subject is not a CA, but andre@0: the pathLenConstraint is set */ andre@0: PORT_SetError (SEC_ERROR_BAD_DER); andre@0: GEN_BREAK (SECFailure); andre@0: break; andre@0: } andre@0: andre@0: } while (0); andre@0: PORT_FreeArena (our_pool, PR_FALSE); andre@0: return (rv); andre@0: andre@0: }