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 v3 Subject Key Usage Extension michael@0: * 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 "secport.h" michael@0: #include "certt.h" michael@0: #include "genname.h" michael@0: #include "secerr.h" michael@0: michael@0: SEC_ASN1_MKSUB(SEC_IntegerTemplate) michael@0: SEC_ASN1_MKSUB(SEC_OctetStringTemplate) michael@0: michael@0: const SEC_ASN1Template CERTAuthKeyIDTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTAuthKeyID) }, michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, michael@0: offsetof(CERTAuthKeyID,keyID), SEC_ASN1_SUB(SEC_OctetStringTemplate)}, michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, michael@0: offsetof(CERTAuthKeyID, DERAuthCertIssuer), CERT_GeneralNamesTemplate}, michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2, michael@0: offsetof(CERTAuthKeyID,authCertSerialNumber), michael@0: SEC_ASN1_SUB(SEC_IntegerTemplate) }, michael@0: { 0 } michael@0: }; michael@0: michael@0: michael@0: michael@0: SECStatus CERT_EncodeAuthKeyID (PLArenaPool *arena, CERTAuthKeyID *value, SECItem *encodedValue) michael@0: { michael@0: SECStatus rv = SECFailure; michael@0: michael@0: PORT_Assert (value); michael@0: PORT_Assert (arena); michael@0: PORT_Assert (value->DERAuthCertIssuer == NULL); michael@0: PORT_Assert (encodedValue); michael@0: michael@0: do { michael@0: michael@0: /* If both of the authCertIssuer and the serial number exist, encode michael@0: the name first. Otherwise, it is an error if one exist and the other michael@0: is not. michael@0: */ michael@0: if (value->authCertIssuer) { michael@0: if (!value->authCertSerialNumber.data) { michael@0: PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); michael@0: break; michael@0: } michael@0: michael@0: value->DERAuthCertIssuer = cert_EncodeGeneralNames michael@0: (arena, value->authCertIssuer); michael@0: if (!value->DERAuthCertIssuer) { michael@0: PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); michael@0: break; michael@0: } michael@0: } michael@0: else if (value->authCertSerialNumber.data) { michael@0: PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); michael@0: break; michael@0: } michael@0: michael@0: if (SEC_ASN1EncodeItem (arena, encodedValue, value, michael@0: CERTAuthKeyIDTemplate) == NULL) michael@0: break; michael@0: rv = SECSuccess; michael@0: michael@0: } while (0); michael@0: return(rv); michael@0: } michael@0: michael@0: CERTAuthKeyID * michael@0: CERT_DecodeAuthKeyID (PLArenaPool *arena, const SECItem *encodedValue) michael@0: { michael@0: CERTAuthKeyID * value = NULL; michael@0: SECStatus rv = SECFailure; michael@0: void * mark; michael@0: SECItem newEncodedValue; michael@0: michael@0: PORT_Assert (arena); michael@0: michael@0: do { michael@0: mark = PORT_ArenaMark (arena); michael@0: value = (CERTAuthKeyID*)PORT_ArenaZAlloc (arena, sizeof (*value)); michael@0: if (value == NULL) michael@0: break; michael@0: value->DERAuthCertIssuer = NULL; 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, &newEncodedValue, encodedValue); michael@0: if ( rv != SECSuccess ) { michael@0: break; michael@0: } michael@0: michael@0: rv = SEC_QuickDERDecodeItem michael@0: (arena, value, CERTAuthKeyIDTemplate, &newEncodedValue); michael@0: if (rv != SECSuccess) michael@0: break; michael@0: michael@0: value->authCertIssuer = cert_DecodeGeneralNames (arena, value->DERAuthCertIssuer); michael@0: if (value->authCertIssuer == NULL) michael@0: break; michael@0: michael@0: /* what if the general name contains other format but not URI ? michael@0: hl michael@0: */ michael@0: if ((value->authCertSerialNumber.data && !value->authCertIssuer) || michael@0: (!value->authCertSerialNumber.data && value->authCertIssuer)){ michael@0: PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); michael@0: break; michael@0: } michael@0: } while (0); michael@0: michael@0: if (rv != SECSuccess) { michael@0: PORT_ArenaRelease (arena, mark); michael@0: return ((CERTAuthKeyID *)NULL); michael@0: } michael@0: PORT_ArenaUnmark(arena, mark); michael@0: return (value); michael@0: }