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: #include "cmmf.h" michael@0: #include "cmmfi.h" michael@0: michael@0: SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) michael@0: SEC_ASN1_MKSUB(SEC_AnyTemplate) michael@0: SEC_ASN1_MKSUB(SEC_IntegerTemplate) michael@0: SEC_ASN1_MKSUB(SEC_SignedCertificateTemplate) michael@0: michael@0: static const SEC_ASN1Template CMMFCertResponseTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFCertResponse)}, michael@0: { SEC_ASN1_INTEGER, offsetof(CMMFCertResponse, certReqId)}, michael@0: { SEC_ASN1_INLINE, offsetof(CMMFCertResponse, status), michael@0: CMMFPKIStatusInfoTemplate}, michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_POINTER, michael@0: offsetof(CMMFCertResponse, certifiedKeyPair), michael@0: CMMFCertifiedKeyPairTemplate}, michael@0: { 0 } michael@0: }; michael@0: michael@0: static const SEC_ASN1Template CMMFCertOrEncCertTemplate[] = { michael@0: { SEC_ASN1_ANY, offsetof(CMMFCertOrEncCert, derValue), NULL, michael@0: sizeof(CMMFCertOrEncCert)}, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template CMMFCertifiedKeyPairTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFCertifiedKeyPair)}, michael@0: { SEC_ASN1_INLINE, offsetof(CMMFCertifiedKeyPair, certOrEncCert), michael@0: CMMFCertOrEncCertTemplate }, michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_POINTER | 0, michael@0: offsetof(CMMFCertifiedKeyPair, privateKey), michael@0: CRMFEncryptedValueTemplate}, michael@0: { SEC_ASN1_NO_STREAM | SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | michael@0: SEC_ASN1_XTRN | 1, michael@0: offsetof (CMMFCertifiedKeyPair, derPublicationInfo), michael@0: SEC_ASN1_SUB(SEC_AnyTemplate) }, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template CMMFPKIStatusInfoTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFPKIStatusInfo)}, michael@0: { SEC_ASN1_INTEGER, offsetof(CMMFPKIStatusInfo, status)}, michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_UTF8_STRING, michael@0: offsetof(CMMFPKIStatusInfo, statusString)}, michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_BIT_STRING, michael@0: offsetof(CMMFPKIStatusInfo, failInfo)}, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template CMMFSequenceOfCertsTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE_OF| SEC_ASN1_XTRN, 0, michael@0: SEC_ASN1_SUB(SEC_SignedCertificateTemplate)} michael@0: }; michael@0: michael@0: const SEC_ASN1Template CMMFRandTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFRand)}, michael@0: { SEC_ASN1_INTEGER, offsetof(CMMFRand, integer)}, michael@0: { SEC_ASN1_OCTET_STRING, offsetof(CMMFRand, senderHash)}, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template CMMFPOPODecKeyRespContentTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, michael@0: offsetof(CMMFPOPODecKeyRespContent, responses), michael@0: SEC_ASN1_SUB(SEC_IntegerTemplate), michael@0: sizeof(CMMFPOPODecKeyRespContent)}, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template CMMFCertOrEncCertEncryptedCertTemplate[] = { michael@0: { SEC_ASN1_CONTEXT_SPECIFIC | 1, michael@0: 0, michael@0: CRMFEncryptedValueTemplate}, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template CMMFCertOrEncCertCertificateTemplate[] = { michael@0: { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, michael@0: 0, michael@0: SEC_ASN1_SUB(SEC_SignedCertificateTemplate)}, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template CMMFCertRepContentTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFCertRepContent)}, michael@0: { SEC_ASN1_CONSTRUCTED | SEC_ASN1_OPTIONAL | michael@0: SEC_ASN1_CONTEXT_SPECIFIC | 1, michael@0: offsetof(CMMFCertRepContent, caPubs), michael@0: CMMFSequenceOfCertsTemplate }, michael@0: { SEC_ASN1_SEQUENCE_OF, offsetof(CMMFCertRepContent, response), michael@0: CMMFCertResponseTemplate}, michael@0: { 0 } michael@0: }; michael@0: michael@0: static const SEC_ASN1Template CMMFChallengeTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CMMFChallenge)}, michael@0: { SEC_ASN1_POINTER | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN, michael@0: offsetof(CMMFChallenge, owf), michael@0: SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, michael@0: { SEC_ASN1_OCTET_STRING, offsetof(CMMFChallenge, witness) }, michael@0: { SEC_ASN1_ANY, offsetof(CMMFChallenge, senderDER) }, michael@0: { SEC_ASN1_OCTET_STRING, offsetof(CMMFChallenge, key) }, michael@0: { SEC_ASN1_OCTET_STRING, offsetof(CMMFChallenge, challenge) }, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template CMMFPOPODecKeyChallContentTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE_OF,offsetof(CMMFPOPODecKeyChallContent, challenges), michael@0: CMMFChallengeTemplate, sizeof(CMMFPOPODecKeyChallContent) }, michael@0: { 0 } michael@0: }; michael@0: michael@0: SECStatus michael@0: cmmf_decode_process_cert_response(PLArenaPool *poolp, michael@0: CERTCertDBHandle *db, michael@0: CMMFCertResponse *inCertResp) michael@0: { michael@0: SECStatus rv = SECSuccess; michael@0: michael@0: if (inCertResp->certifiedKeyPair != NULL) { michael@0: rv = cmmf_decode_process_certified_key_pair(poolp, michael@0: db, michael@0: inCertResp->certifiedKeyPair); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: static CERTCertificate* michael@0: cmmf_DecodeDERCertificate(CERTCertDBHandle *db, SECItem *derCert) michael@0: { michael@0: CERTCertificate *newCert; michael@0: michael@0: newCert = CERT_NewTempCertificate(db, derCert, NULL, PR_FALSE, PR_TRUE); michael@0: return newCert; michael@0: } michael@0: michael@0: static CMMFCertOrEncCertChoice michael@0: cmmf_get_certorenccertchoice_from_der(SECItem *der) michael@0: { michael@0: CMMFCertOrEncCertChoice retChoice; michael@0: michael@0: switch(der->data[0] & 0x0f) { michael@0: case 0: michael@0: retChoice = cmmfCertificate; michael@0: break; michael@0: case 1: michael@0: retChoice = cmmfEncryptedCert; michael@0: break; michael@0: default: michael@0: retChoice = cmmfNoCertOrEncCert; michael@0: break; michael@0: } michael@0: return retChoice; michael@0: } michael@0: michael@0: static SECStatus michael@0: cmmf_decode_process_certorenccert(PLArenaPool *poolp, michael@0: CERTCertDBHandle *db, michael@0: CMMFCertOrEncCert *inCertOrEncCert) michael@0: { michael@0: SECStatus rv = SECSuccess; michael@0: michael@0: inCertOrEncCert->choice = michael@0: cmmf_get_certorenccertchoice_from_der(&inCertOrEncCert->derValue); michael@0: michael@0: switch (inCertOrEncCert->choice) { michael@0: case cmmfCertificate: michael@0: { michael@0: /* The DER has implicit tagging, so we gotta switch it to michael@0: * un-tagged in order for the ASN1 parser to understand it. michael@0: * Saving the bits that were changed. michael@0: */ michael@0: inCertOrEncCert->derValue.data[0] = 0x30; michael@0: inCertOrEncCert->cert.certificate = michael@0: cmmf_DecodeDERCertificate(db, &inCertOrEncCert->derValue); michael@0: if (inCertOrEncCert->cert.certificate == NULL) { michael@0: rv = SECFailure; michael@0: } michael@0: michael@0: } michael@0: break; michael@0: case cmmfEncryptedCert: michael@0: PORT_Assert(poolp); michael@0: if (!poolp) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: inCertOrEncCert->cert.encryptedCert = michael@0: PORT_ArenaZNew(poolp, CRMFEncryptedValue); michael@0: if (inCertOrEncCert->cert.encryptedCert == NULL) { michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: rv = SEC_ASN1Decode(poolp, inCertOrEncCert->cert.encryptedCert, michael@0: CMMFCertOrEncCertEncryptedCertTemplate, michael@0: (const char*)inCertOrEncCert->derValue.data, michael@0: inCertOrEncCert->derValue.len); michael@0: break; michael@0: default: michael@0: rv = SECFailure; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: SECStatus michael@0: cmmf_decode_process_certified_key_pair(PLArenaPool *poolp, michael@0: CERTCertDBHandle *db, michael@0: CMMFCertifiedKeyPair *inCertKeyPair) michael@0: { michael@0: return cmmf_decode_process_certorenccert (poolp, michael@0: db, michael@0: &inCertKeyPair->certOrEncCert); michael@0: } michael@0: michael@0: