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 Extension Encoding andre@0: */ andre@0: andre@0: #include "prtypes.h" 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 "cert.h" andre@0: #include "secder.h" andre@0: #include "prprf.h" andre@0: #include "xconst.h" andre@0: #include "genname.h" andre@0: #include "secasn1.h" andre@0: #include "secerr.h" andre@0: andre@0: andre@0: static const SEC_ASN1Template CERTSubjectKeyIDTemplate[] = { andre@0: { SEC_ASN1_OCTET_STRING } andre@0: }; andre@0: andre@0: andre@0: static const SEC_ASN1Template CERTIA5TypeTemplate[] = { andre@0: { SEC_ASN1_IA5_STRING } andre@0: }; andre@0: andre@0: SEC_ASN1_MKSUB(SEC_GeneralizedTimeTemplate) andre@0: andre@0: static const SEC_ASN1Template CERTPrivateKeyUsagePeriodTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, andre@0: 0, NULL, sizeof(CERTPrivKeyUsagePeriod) }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, andre@0: offsetof(CERTPrivKeyUsagePeriod, notBefore), andre@0: SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate) }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1, andre@0: offsetof(CERTPrivKeyUsagePeriod, notAfter), andre@0: SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate)}, andre@0: { 0, } andre@0: }; andre@0: andre@0: andre@0: const SEC_ASN1Template CERTAltNameTemplate[] = { andre@0: { SEC_ASN1_CONSTRUCTED, offsetof(CERTAltNameEncodedContext, encodedGenName), andre@0: CERT_GeneralNamesTemplate} andre@0: }; andre@0: andre@0: const SEC_ASN1Template CERTAuthInfoAccessItemTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, andre@0: 0, NULL, sizeof(CERTAuthInfoAccess) }, andre@0: { SEC_ASN1_OBJECT_ID, andre@0: offsetof(CERTAuthInfoAccess, method) }, andre@0: { SEC_ASN1_ANY, andre@0: offsetof(CERTAuthInfoAccess, derLocation) }, andre@0: { 0, } andre@0: }; andre@0: andre@0: const SEC_ASN1Template CERTAuthInfoAccessTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE_OF, 0, CERTAuthInfoAccessItemTemplate } andre@0: }; andre@0: andre@0: andre@0: SECStatus andre@0: CERT_EncodeSubjectKeyID(PLArenaPool *arena, const SECItem* srcString, andre@0: SECItem *encodedValue) andre@0: { andre@0: SECStatus rv = SECSuccess; andre@0: andre@0: if (!srcString) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: if (SEC_ASN1EncodeItem (arena, encodedValue, srcString, andre@0: CERTSubjectKeyIDTemplate) == NULL) { andre@0: rv = SECFailure; andre@0: } andre@0: andre@0: return(rv); andre@0: } andre@0: andre@0: andre@0: SECStatus andre@0: CERT_EncodePrivateKeyUsagePeriod(PLArenaPool *arena, andre@0: CERTPrivKeyUsagePeriod *pkup, andre@0: SECItem *encodedValue) andre@0: { andre@0: SECStatus rv = SECSuccess; andre@0: andre@0: if (SEC_ASN1EncodeItem (arena, encodedValue, pkup, andre@0: CERTPrivateKeyUsagePeriodTemplate) == NULL) { andre@0: rv = SECFailure; andre@0: } andre@0: return(rv); andre@0: } andre@0: andre@0: CERTPrivKeyUsagePeriod * andre@0: CERT_DecodePrivKeyUsagePeriodExtension(PLArenaPool *arena, SECItem *extnValue) andre@0: { andre@0: SECStatus rv; andre@0: CERTPrivKeyUsagePeriod *pPeriod; andre@0: SECItem newExtnValue; andre@0: andre@0: /* allocate the certificate policies structure */ andre@0: pPeriod = PORT_ArenaZNew(arena, CERTPrivKeyUsagePeriod); andre@0: if ( pPeriod == NULL ) { andre@0: goto loser; andre@0: } andre@0: andre@0: pPeriod->arena = arena; andre@0: andre@0: /* copy the DER into the arena, since Quick DER returns data that points andre@0: into the DER input, which may get freed by the caller */ andre@0: rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue); andre@0: if ( rv != SECSuccess ) { andre@0: goto loser; andre@0: } andre@0: andre@0: rv = SEC_QuickDERDecodeItem(arena, pPeriod, andre@0: CERTPrivateKeyUsagePeriodTemplate, andre@0: &newExtnValue); andre@0: if ( rv != SECSuccess ) { andre@0: goto loser; andre@0: } andre@0: return pPeriod; andre@0: andre@0: loser: andre@0: return NULL; andre@0: } andre@0: andre@0: andre@0: SECStatus andre@0: CERT_EncodeIA5TypeExtension(PLArenaPool *arena, char *value, SECItem *encodedValue) andre@0: { andre@0: SECItem encodeContext; andre@0: SECStatus rv = SECSuccess; andre@0: andre@0: andre@0: PORT_Memset (&encodeContext, 0, sizeof (encodeContext)); andre@0: andre@0: if (value != NULL) { andre@0: encodeContext.data = (unsigned char *)value; andre@0: encodeContext.len = strlen(value); andre@0: } andre@0: if (SEC_ASN1EncodeItem (arena, encodedValue, &encodeContext, andre@0: CERTIA5TypeTemplate) == NULL) { andre@0: rv = SECFailure; andre@0: } andre@0: andre@0: return(rv); andre@0: } andre@0: andre@0: SECStatus andre@0: CERT_EncodeAltNameExtension(PLArenaPool *arena, CERTGeneralName *value, SECItem *encodedValue) andre@0: { andre@0: SECItem **encodedGenName; andre@0: SECStatus rv = SECSuccess; andre@0: andre@0: encodedGenName = cert_EncodeGeneralNames(arena, value); andre@0: if (SEC_ASN1EncodeItem (arena, encodedValue, &encodedGenName, andre@0: CERT_GeneralNamesTemplate) == NULL) { andre@0: rv = SECFailure; andre@0: } andre@0: andre@0: return rv; andre@0: } andre@0: andre@0: CERTGeneralName * andre@0: CERT_DecodeAltNameExtension(PLArenaPool *reqArena, SECItem *EncodedAltName) andre@0: { andre@0: SECStatus rv = SECSuccess; andre@0: CERTAltNameEncodedContext encodedContext; andre@0: SECItem* newEncodedAltName; andre@0: andre@0: if (!reqArena) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: andre@0: newEncodedAltName = SECITEM_ArenaDupItem(reqArena, EncodedAltName); andre@0: if (!newEncodedAltName) { andre@0: return NULL; andre@0: } andre@0: andre@0: encodedContext.encodedGenName = NULL; andre@0: PORT_Memset(&encodedContext, 0, sizeof(CERTAltNameEncodedContext)); andre@0: rv = SEC_QuickDERDecodeItem (reqArena, &encodedContext, andre@0: CERT_GeneralNamesTemplate, newEncodedAltName); andre@0: if (rv == SECFailure) { andre@0: goto loser; andre@0: } andre@0: if (encodedContext.encodedGenName && encodedContext.encodedGenName[0]) andre@0: return cert_DecodeGeneralNames(reqArena, andre@0: encodedContext.encodedGenName); andre@0: /* Extension contained an empty GeneralNames sequence */ andre@0: /* Treat as extension not found */ andre@0: PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND); andre@0: loser: andre@0: return NULL; andre@0: } andre@0: andre@0: andre@0: SECStatus andre@0: CERT_EncodeNameConstraintsExtension(PLArenaPool *arena, andre@0: CERTNameConstraints *value, andre@0: SECItem *encodedValue) andre@0: { andre@0: SECStatus rv = SECSuccess; andre@0: andre@0: rv = cert_EncodeNameConstraints(value, arena, encodedValue); andre@0: return rv; andre@0: } andre@0: andre@0: andre@0: CERTNameConstraints * andre@0: CERT_DecodeNameConstraintsExtension(PLArenaPool *arena, andre@0: const SECItem *encodedConstraints) andre@0: { andre@0: return cert_DecodeNameConstraints(arena, encodedConstraints); andre@0: } andre@0: andre@0: andre@0: CERTAuthInfoAccess ** andre@0: CERT_DecodeAuthInfoAccessExtension(PLArenaPool *reqArena, andre@0: SECItem *encodedExtension) andre@0: { andre@0: CERTAuthInfoAccess **info = NULL; andre@0: SECStatus rv; andre@0: int i; andre@0: SECItem* newEncodedExtension; andre@0: andre@0: if (!reqArena) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: andre@0: newEncodedExtension = SECITEM_ArenaDupItem(reqArena, encodedExtension); andre@0: if (!newEncodedExtension) { andre@0: return NULL; andre@0: } andre@0: andre@0: rv = SEC_QuickDERDecodeItem(reqArena, &info, CERTAuthInfoAccessTemplate, andre@0: newEncodedExtension); andre@0: if (rv != SECSuccess || info == NULL) { andre@0: return NULL; andre@0: } andre@0: andre@0: for (i = 0; info[i] != NULL; i++) { andre@0: info[i]->location = CERT_DecodeGeneralName(reqArena, andre@0: &(info[i]->derLocation), andre@0: NULL); andre@0: } andre@0: return info; andre@0: } andre@0: andre@0: SECStatus andre@0: CERT_EncodeInfoAccessExtension(PLArenaPool *arena, andre@0: CERTAuthInfoAccess **info, andre@0: SECItem *dest) andre@0: { andre@0: SECItem *dummy; andre@0: int i; andre@0: andre@0: PORT_Assert(info != NULL); andre@0: PORT_Assert(dest != NULL); andre@0: if (info == NULL || dest == NULL) { andre@0: return SECFailure; andre@0: } andre@0: andre@0: for (i = 0; info[i] != NULL; i++) { andre@0: if (CERT_EncodeGeneralName(info[i]->location, &(info[i]->derLocation), andre@0: arena) == NULL) andre@0: /* Note that this may leave some of the locations filled in. */ andre@0: return SECFailure; andre@0: } andre@0: dummy = SEC_ASN1EncodeItem(arena, dest, &info, andre@0: CERTAuthInfoAccessTemplate); andre@0: if (dummy == NULL) { andre@0: return SECFailure; andre@0: } andre@0: return SECSuccess; andre@0: }