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