OSStatus SecCmsSignedDataAddDigest(SecArenaPoolRef pool, SecCmsSignedDataRef sigd, SECOidTag digestalgtag, CSSM_DATA_PTR digest) { PRArenaPool *poolp = (PRArenaPool *)pool; SECAlgorithmID *digestalg; void *mark; mark = PORT_ArenaMark(poolp); digestalg = PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID)); if (digestalg == NULL) goto loser; if (SECOID_SetAlgorithmID (poolp, digestalg, digestalgtag, NULL) != SECSuccess) /* no params */ goto loser; if (SecCmsArrayAdd(poolp, (void ***)&(sigd->digestAlgorithms), (void *)digestalg) != SECSuccess || /* even if digest is NULL, add dummy to have same-size array */ SecCmsArrayAdd(poolp, (void ***)&(sigd->digests), (void *)digest) != SECSuccess) { goto loser; } PORT_ArenaUnmark(poolp, mark); return SECSuccess; loser: PORT_ArenaRelease(poolp, mark); return SECFailure; }
nsresult PublicDhKeyToSpki(SECKEYPublicKey* aPubKey, CERTSubjectPublicKeyInfo* aSpki) { SECItem* params = ::SECITEM_AllocItem(aSpki->arena, nullptr, 0); if (!params) { return NS_ERROR_DOM_OPERATION_ERR; } SECItem* rvItem = SEC_ASN1EncodeItem(aSpki->arena, params, aPubKey, SECKEY_DHParamKeyTemplate); if (!rvItem) { return NS_ERROR_DOM_OPERATION_ERR; } SECStatus rv = SECOID_SetAlgorithmID(aSpki->arena, &aSpki->algorithm, SEC_OID_X942_DIFFIE_HELMAN_KEY, params); if (rv != SECSuccess) { return NS_ERROR_DOM_OPERATION_ERR; } rvItem = SEC_ASN1EncodeItem(aSpki->arena, &aSpki->subjectPublicKey, aPubKey, SECKEY_DHPublicKeyTemplate); if (!rvItem) { return NS_ERROR_DOM_OPERATION_ERR; } // The public value is a BIT_STRING encoded as an INTEGER. After encoding // an INT we need to adjust the length to reflect the number of bits. aSpki->subjectPublicKey.len <<= 3; return NS_OK; }
/******************************************************************** * * s i g n _ c e r t */ static SECItem * sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk) { SECStatus rv; SECItem der2; SECItem * result2; void *dummy; SECOidTag alg = SEC_OID_UNKNOWN; alg = SEC_GetSignatureAlgorithmOidTag(privk->keyType, SEC_OID_UNKNOWN); if (alg == SEC_OID_UNKNOWN) { FatalError("Unknown key type"); } rv = SECOID_SetAlgorithmID (cert->arena, &cert->signature, alg, 0); if (rv != SECSuccess) { PR_fprintf(errorFD, "%s: unable to set signature alg id\n", PROGRAM_NAME); errorCount++; exit (ERRX); } der2.len = 0; der2.data = NULL; dummy = SEC_ASN1EncodeItem (cert->arena, &der2, cert, SEC_ASN1_GET(CERT_CertificateTemplate)); if (rv != SECSuccess) { PR_fprintf(errorFD, "%s: error encoding cert\n", PROGRAM_NAME); errorCount++; exit (ERRX); } result2 = (SECItem * ) PORT_ArenaZAlloc (cert->arena, sizeof (SECItem)); if (result2 == NULL) out_of_memory(); rv = SEC_DerSignData (cert->arena, result2, der2.data, der2.len, privk, alg); if (rv != SECSuccess) { PR_fprintf(errorFD, "can't sign encoded certificate data\n"); errorCount++; exit (ERRX); } else if (verbosity >= 0) { PR_fprintf(outputFD, "certificate has been signed\n"); } cert->derCert = *result2; return result2; }
SECStatus SEC_DerSignData(PRArenaPool *arena, SECItem *result, unsigned char *buf, int len, SECKEYPrivateKey *pk, SECOidTag algID) { SECItem it; CERTSignedData sd; SECStatus rv; it.data = 0; /* XXX We should probably have some asserts here to make sure the key type * and algID match */ if (algID == SEC_OID_UNKNOWN) { switch(pk->keyType) { case rsaKey: algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break; case dsaKey: algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; break; case ecKey: algID = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST; break; default: PORT_SetError(SEC_ERROR_INVALID_KEY); return SECFailure; } } /* Sign input buffer */ rv = SEC_SignData(&it, buf, len, pk, algID); if (rv) goto loser; /* Fill out SignedData object */ PORT_Memset(&sd, 0, sizeof(sd)); sd.data.data = buf; sd.data.len = len; sd.signature.data = it.data; sd.signature.len = it.len << 3; /* convert to bit string */ rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0); if (rv) goto loser; /* DER encode the signed data object */ rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd); /* FALL THROUGH */ loser: PORT_Free(it.data); return rv; }
OSStatus SecCmsContentInfoSetContentEncAlg(SecArenaPoolRef pool, SecCmsContentInfoRef cinfo, SECOidTag bulkalgtag, CSSM_DATA_PTR parameters, int keysize) { PLArenaPool *poolp = (PLArenaPool *)pool; OSStatus rv; rv = SECOID_SetAlgorithmID(poolp, &(cinfo->contentEncAlg), bulkalgtag, parameters); if (rv != SECSuccess) return SECFailure; cinfo->keysize = keysize; return SECSuccess; }
SECStatus NSS_CMSContentInfo_SetContentEncAlg(PLArenaPool *poolp, NSSCMSContentInfo *cinfo, SECOidTag bulkalgtag, SECItem *parameters, int keysize) { SECStatus rv; if (cinfo == NULL) { return SECFailure; } rv = SECOID_SetAlgorithmID(poolp, &(cinfo->contentEncAlg), bulkalgtag, parameters); if (rv != SECSuccess) { return SECFailure; } cinfo->keysize = keysize; return SECSuccess; }
int crypto_cert_get_pub_exp_mod(CryptoCert cert, uint32 * key_len, uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len) { SECKEYPublicKey * pubkey; SECOidTag tag = SECOID_GetAlgorithmTag(&cert->cert->subjectPublicKeyInfo.algorithm); if ((tag == SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION) || (tag == SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE)) { /* For some reason, Microsoft sets the OID of the Public RSA key to the oid for "MD5 with RSA Encryption" instead of "RSA Encryption". */ SECAlgorithmID org = cert->cert->subjectPublicKeyInfo.algorithm; SECStatus s = SECOID_SetAlgorithmID(cert->cert->subjectPublicKeyInfo.arena, &cert->cert->subjectPublicKeyInfo.algorithm, SEC_OID_PKCS1_RSA_ENCRYPTION, NULL); check(s, "Error setting temp algo oid"); pubkey = SECKEY_ExtractPublicKey(&cert->cert->subjectPublicKeyInfo); SECOID_DestroyAlgorithmID(&cert->cert->subjectPublicKeyInfo.algorithm, False); cert->cert->subjectPublicKeyInfo.algorithm = org; } else { pubkey = SECKEY_ExtractPublicKey(&cert->cert->subjectPublicKeyInfo); } ASSERT(pubkey); ASSERT(pubkey->keyType == rsaKey); *key_len = SECKEY_PublicKeyStrength(pubkey); size_t l = pubkey->u.rsa.publicExponent.len; ASSERT(l <= exp_len); memset(exponent, 0, exp_len - l); memcpy(exponent + exp_len - l, pubkey->u.rsa.publicExponent.data, l); l = pubkey->u.rsa.modulus.len; ASSERT(l <= mod_len); ASSERT(*key_len <= mod_len); memset(modulus, 0, *key_len - l); memcpy(modulus + *key_len - l, pubkey->u.rsa.modulus.data, l); SECKEY_DestroyPublicKey(pubkey); return 0; }
SECStatus NSS_CMSSignedData_AddDigest(PLArenaPool *poolp, NSSCMSSignedData *sigd, SECOidTag digestalgtag, SECItem *digest) { SECAlgorithmID *digestalg; void *mark; if (!sigd || !poolp) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } mark = PORT_ArenaMark(poolp); digestalg = PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID)); if (digestalg == NULL) goto loser; if (SECOID_SetAlgorithmID(poolp, digestalg, digestalgtag, NULL) != SECSuccess) /* no params */ goto loser; if (NSS_CMSArray_Add(poolp, (void ***)&(sigd->digestAlgorithms), (void *)digestalg) != SECSuccess || /* even if digest is NULL, add dummy to have same-size array */ NSS_CMSArray_Add(poolp, (void ***)&(sigd->digests), (void *)digest) != SECSuccess) { goto loser; } PORT_ArenaUnmark(poolp, mark); return SECSuccess; loser: PORT_ArenaRelease(poolp, mark); return SECFailure; }
static nsresult GetAttestationCertificate(const UniquePK11SlotInfo& aSlot, /*out*/ UniqueSECKEYPrivateKey& aAttestPrivKey, /*out*/ UniqueCERTCertificate& aAttestCert, const nsNSSShutDownPreventionLock& locker) { MOZ_ASSERT(aSlot); if (NS_WARN_IF(!aSlot)) { return NS_ERROR_INVALID_ARG; } UniqueSECKEYPublicKey pubKey; // Construct an ephemeral keypair for this Attestation Certificate nsresult rv = GenEcKeypair(aSlot, aAttestPrivKey, pubKey, locker); if (NS_WARN_IF(NS_FAILED(rv) || !aAttestPrivKey || !pubKey)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to gen keypair, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } // Construct the Attestation Certificate itself UniqueCERTName subjectName(CERT_AsciiToName(kAttestCertSubjectName.get())); if (NS_WARN_IF(!subjectName)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to set subject name, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } UniqueCERTSubjectPublicKeyInfo spki( SECKEY_CreateSubjectPublicKeyInfo(pubKey.get())); if (NS_WARN_IF(!spki)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to set SPKI, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } UniqueCERTCertificateRequest certreq( CERT_CreateCertificateRequest(subjectName.get(), spki.get(), nullptr)); if (NS_WARN_IF(!certreq)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to gen CSR, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } PRTime now = PR_Now(); PRTime notBefore = now - kExpirationSlack; PRTime notAfter = now + kExpirationLife; UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter)); if (NS_WARN_IF(!validity)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to gen validity, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } unsigned long serial; unsigned char* serialBytes = mozilla::BitwiseCast<unsigned char*, unsigned long*>(&serial); SECStatus srv = PK11_GenerateRandomOnSlot(aSlot.get(), serialBytes, sizeof(serial)); if (NS_WARN_IF(srv != SECSuccess)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to gen serial, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } // Ensure that the most significant bit isn't set (which would // indicate a negative number, which isn't valid for serial // numbers). serialBytes[0] &= 0x7f; // Also ensure that the least significant bit on the most // significant byte is set (to prevent a leading zero byte, // which also wouldn't be valid). serialBytes[0] |= 0x01; aAttestCert = UniqueCERTCertificate( CERT_CreateCertificate(serial, subjectName.get(), validity.get(), certreq.get())); if (NS_WARN_IF(!aAttestCert)) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to gen certificate, NSS error #%d", PORT_GetError())); return NS_ERROR_FAILURE; } PLArenaPool* arena = aAttestCert->arena; srv = SECOID_SetAlgorithmID(arena, &aAttestCert->signature, SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, /* wincx */ nullptr); if (NS_WARN_IF(srv != SECSuccess)) { return NS_ERROR_FAILURE; } // Set version to X509v3. *(aAttestCert->version.data) = SEC_CERTIFICATE_VERSION_3; aAttestCert->version.len = 1; SECItem innerDER = { siBuffer, nullptr, 0 }; if (NS_WARN_IF(!SEC_ASN1EncodeItem(arena, &innerDER, aAttestCert.get(), SEC_ASN1_GET(CERT_CertificateTemplate)))) { return NS_ERROR_FAILURE; } SECItem* signedCert = PORT_ArenaZNew(arena, SECItem); if (NS_WARN_IF(!signedCert)) { return NS_ERROR_FAILURE; } srv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len, aAttestPrivKey.get(), SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE); if (NS_WARN_IF(srv != SECSuccess)) { return NS_ERROR_FAILURE; } aAttestCert->derCert = *signedCert; MOZ_LOG(gNSSTokenLog, LogLevel::Debug, ("U2F Soft Token attestation certificate generated.")); return NS_OK; }
int main(int argc, char **argv) { int verbose=0, force=0; int ascii=0, issuerAscii=0; char *progName=0; PRFileDesc *inFile=0, *issuerCertFile=0; SECItem derCert, derIssuerCert; PLArenaPool *arena=0; CERTSignedData *signedData=0; CERTCertificate *cert=0, *issuerCert=0; SECKEYPublicKey *rsapubkey=0; SECAlgorithmID md5WithRSAEncryption, md2WithRSAEncryption; SECAlgorithmID sha1WithRSAEncryption, rsaEncryption; SECItem spk; int selfSigned=0; int invalid=0; char *inFileName = NULL, *issuerCertFileName = NULL; PLOptState *optstate; PLOptStatus status; SECStatus rv; PORT_Memset(&md5WithRSAEncryption, 0, sizeof(md5WithRSAEncryption)); PORT_Memset(&md2WithRSAEncryption, 0, sizeof(md2WithRSAEncryption)); PORT_Memset(&sha1WithRSAEncryption, 0, sizeof(sha1WithRSAEncryption)); PORT_Memset(&rsaEncryption, 0, sizeof(rsaEncryption)); progName = strrchr(argv[0], '/'); progName = progName ? progName+1 : argv[0]; optstate = PL_CreateOptState(argc, argv, "aAvf"); while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { switch (optstate->option) { case 'v': verbose = 1; break; case 'f': force = 1; break; case 'a': ascii = 1; break; case 'A': issuerAscii = 1; break; case '\0': if (!inFileName) inFileName = PL_strdup(optstate->value); else if (!issuerCertFileName) issuerCertFileName = PL_strdup(optstate->value); else Usage(progName); break; } } if (!inFileName || !issuerCertFileName || status == PL_OPT_BAD) { /* insufficient or excess args */ Usage(progName); } inFile = PR_Open(inFileName, PR_RDONLY, 0); if (!inFile) { fprintf(stderr, "%s: unable to open \"%s\" for reading\n", progName, inFileName); exit(1); } issuerCertFile = PR_Open(issuerCertFileName, PR_RDONLY, 0); if (!issuerCertFile) { fprintf(stderr, "%s: unable to open \"%s\" for reading\n", progName, issuerCertFileName); exit(1); } if (SECU_ReadDERFromFile(&derCert, inFile, ascii, PR_FALSE) != SECSuccess) { printf("Couldn't read input certificate as DER binary or base64\n"); exit(1); } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == 0) { fprintf(stderr,"%s: can't allocate scratch arena!", progName); exit(1); } if (issuerCertFile) { CERTSignedData *issuerCertSD=0; if (SECU_ReadDERFromFile(&derIssuerCert, issuerCertFile, issuerAscii, PR_FALSE) != SECSuccess) { printf("Couldn't read issuer certificate as DER binary or base64.\n"); exit(1); } issuerCertSD = PORT_ArenaZNew(arena, CERTSignedData); if (!issuerCertSD) { fprintf(stderr,"%s: can't allocate issuer signed data!", progName); exit(1); } rv = SEC_ASN1DecodeItem(arena, issuerCertSD, SEC_ASN1_GET(CERT_SignedDataTemplate), &derIssuerCert); if (rv) { fprintf(stderr, "%s: Issuer cert isn't X509 SIGNED Data?\n", progName); exit(1); } issuerCert = createEmptyCertificate(); if (!issuerCert) { printf("%s: can't allocate space for issuer cert.", progName); exit(1); } rv = SEC_ASN1DecodeItem(arena, issuerCert, SEC_ASN1_GET(CERT_CertificateTemplate), &issuerCertSD->data); if (rv) { printf("%s: Does not appear to be an X509 Certificate.\n", progName); exit(1); } } signedData = PORT_ArenaZNew(arena,CERTSignedData); if (!signedData) { fprintf(stderr,"%s: can't allocate signedData!", progName); exit(1); } rv = SEC_ASN1DecodeItem(arena, signedData, SEC_ASN1_GET(CERT_SignedDataTemplate), &derCert); if (rv) { fprintf(stderr, "%s: Does not appear to be X509 SIGNED Data.\n", progName); exit(1); } if (verbose) { printf("Decoded ok as X509 SIGNED data.\n"); } cert = createEmptyCertificate(); if (!cert) { fprintf(stderr, "%s: can't allocate cert", progName); exit(1); } rv = SEC_ASN1DecodeItem(arena, cert, SEC_ASN1_GET(CERT_CertificateTemplate), &signedData->data); if (rv) { fprintf(stderr, "%s: Does not appear to be an X509 Certificate.\n", progName); exit(1); } if (verbose) { printf("Decoded ok as an X509 certificate.\n"); } SECU_RegisterDynamicOids(); rv = SECU_PrintSignedData(stdout, &derCert, "Certificate", 0, (SECU_PPFunc)SECU_PrintCertificate); if (rv) { fprintf(stderr, "%s: Unable to pretty print cert. Error: %d\n", progName, PORT_GetError()); if (!force) { exit(1); } } /* Do various checks on the cert */ printf("\n"); /* Check algorithms */ rv = SECOID_SetAlgorithmID(arena, &md5WithRSAEncryption, SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, NULL); if (rv) { fprintf(stderr, "%s: failed to set algorithm ID for SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION.\n", progName); exit(1); } rv = SECOID_SetAlgorithmID(arena, &md2WithRSAEncryption, SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION, NULL); if (rv) { fprintf(stderr, "%s: failed to set algorithm ID for SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION.\n", progName); exit(1); } rv = SECOID_SetAlgorithmID(arena, &sha1WithRSAEncryption, SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, NULL); if (rv) { fprintf(stderr, "%s: failed to set algorithm ID for SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION.\n", progName); exit(1); } rv = SECOID_SetAlgorithmID(arena, &rsaEncryption, SEC_OID_PKCS1_RSA_ENCRYPTION, NULL); if (rv) { fprintf(stderr, "%s: failed to set algorithm ID for SEC_OID_PKCS1_RSA_ENCRYPTION.\n", progName); exit(1); } { int isMD5RSA = (SECOID_CompareAlgorithmID(&cert->signature, &md5WithRSAEncryption) == 0); int isMD2RSA = (SECOID_CompareAlgorithmID(&cert->signature, &md2WithRSAEncryption) == 0); int isSHA1RSA = (SECOID_CompareAlgorithmID(&cert->signature, &sha1WithRSAEncryption) == 0); if (verbose) { printf("\nDoing algorithm checks.\n"); } if (!(isMD5RSA || isMD2RSA || isSHA1RSA)) { printf("PROBLEM: Signature not PKCS1 MD5, MD2, or SHA1 + RSA.\n"); } else if (!isMD5RSA) { printf("WARNING: Signature not PKCS1 MD5 with RSA Encryption\n"); } if (SECOID_CompareAlgorithmID(&cert->signature, &signedData->signatureAlgorithm)) { printf("PROBLEM: Algorithm in sig and certInfo don't match.\n"); } } if (SECOID_CompareAlgorithmID(&cert->subjectPublicKeyInfo.algorithm, &rsaEncryption)) { printf("PROBLEM: Public key algorithm is not PKCS1 RSA Encryption.\n"); } /* Check further public key properties */ spk = cert->subjectPublicKeyInfo.subjectPublicKey; DER_ConvertBitString(&spk); if (verbose) { printf("\nsubjectPublicKey DER\n"); rv = DER_PrettyPrint(stdout, &spk, PR_FALSE); printf("\n"); } rsapubkey = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena,sizeof(SECKEYPublicKey)); if (!rsapubkey) { fprintf(stderr, "%s: rsapubkey allocation failed.\n", progName); exit(1); } rv = SEC_ASN1DecodeItem(arena, rsapubkey, SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate), &spk); if (rv) { printf("PROBLEM: subjectPublicKey is not a DER PKCS1 RSAPublicKey.\n"); } else { int mlen; int pubexp; if (verbose) { printf("Decoded RSA Public Key ok. Doing key checks.\n"); } PORT_Assert(rsapubkey->keyType == rsaKey); /* XXX RSA */ mlen = checkInteger(&rsapubkey->u.rsa.modulus, "Modulus", verbose); printf("INFO: Public Key modulus length in bits: %d\n", mlen); if (mlen > MAX_MODULUS) { printf("PROBLEM: Modulus length exceeds %d bits.\n", MAX_MODULUS); } if (mlen < 512) { printf("WARNING: Short modulus.\n"); } if (mlen != (1 << (ffs(mlen)-1))) { printf("WARNING: Unusual modulus length (not a power of two).\n"); } checkInteger(&rsapubkey->u.rsa.publicExponent, "Public Exponent", verbose); pubexp = DER_GetInteger(&rsapubkey->u.rsa.publicExponent); if (pubexp != 17 && pubexp != 3 && pubexp != 65537) { printf("WARNING: Public exponent not any of: 3, 17, 65537\n"); } } /* Name checks */ checkName(&cert->issuer, "Issuer Name", verbose); checkName(&cert->subject, "Subject Name", verbose); if (issuerCert) { SECComparison c = CERT_CompareName(&cert->issuer, &issuerCert->subject); if (c) { printf("PROBLEM: Issuer Name and Subject in Issuing Cert differ\n"); } } /* Check if self-signed */ selfSigned = (CERT_CompareName(&cert->issuer, &cert->subject) == 0); if (selfSigned) { printf("INFO: Certificate is self signed.\n"); } else { printf("INFO: Certificate is NOT self-signed.\n"); } /* Validity time check */ if (CERT_CertTimesValid(cert) == SECSuccess) { printf("INFO: Inside validity period of certificate.\n"); } else { printf("PROBLEM: Not in validity period of certificate.\n"); invalid = 1; } /* Signature check if self-signed */ if (selfSigned && !invalid) { if (rsapubkey->u.rsa.modulus.len) { SECStatus ver; if (verbose) { printf("Checking self signature.\n"); } ver = OurVerifySignedData(signedData, cert); if (ver != SECSuccess) { printf("PROBLEM: Verification of self-signature failed!\n"); } else { printf("INFO: Self-signature verifies ok.\n"); } } else { printf("INFO: Not checking signature due to key problems.\n"); } } else if (!selfSigned && !invalid && issuerCert) { SECStatus ver; ver = OurVerifySignedData(signedData, issuerCert); if (ver != SECSuccess) { printf("PROBLEM: Verification of issuer's signature failed!\n"); } else { printf("INFO: Issuer's signature verifies ok.\n"); } } else { printf("INFO: Not checking signature.\n"); } return 0; }
SECStatus NSS_CMSUtil_EncryptSymKey_ESDH(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *key, SECItem *encKey, SECItem **ukm, SECAlgorithmID *keyEncAlg, SECItem *pubKey) { #if 0 /* not yet done */ SECOidTag certalgtag; /* the certificate's encryption algorithm */ SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */ SECStatus rv; SECItem *params = NULL; int data_len; SECStatus err; PK11SymKey *tek; CERTCertificate *ourCert; SECKEYPublicKey *ourPubKey; NSSCMSKEATemplateSelector whichKEA = NSSCMSKEAInvalid; certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); PORT_Assert(certalgtag == SEC_OID_X942_DIFFIE_HELMAN_KEY); /* We really want to show our KEA tag as the key exchange algorithm tag. */ encalgtag = SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN; /* Get the public key of the recipient. */ publickey = CERT_ExtractPublicKey(cert); if (publickey == NULL) goto loser; /* XXXX generate a DH key pair on a PKCS11 module (XXX which parameters?) */ /* XXXX */ourCert = PK11_FindBestKEAMatch(cert, wincx); if (ourCert == NULL) goto loser; arena = PORT_NewArena(1024); if (arena == NULL) goto loser; /* While we're here, extract the key pair's public key data and copy it into */ /* the outgoing parameters. */ /* XXXX */ourPubKey = CERT_ExtractPublicKey(ourCert); if (ourPubKey == NULL) { goto loser; } SECITEM_CopyItem(arena, pubKey, /* XXX */&(ourPubKey->u.fortezza.KEAKey)); SECKEY_DestroyPublicKey(ourPubKey); /* we only need the private key from now on */ ourPubKey = NULL; /* Extract our private key in order to derive the KEA key. */ ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx); CERT_DestroyCertificate(ourCert); /* we're done with this */ if (!ourPrivKey) goto loser; /* If ukm desired, prepare it - allocate enough space (filled with zeros). */ if (ukm) { ukm->data = (unsigned char*)PORT_ArenaZAlloc(arena,/* XXXX */); ukm->len = /* XXXX */; } /* Generate the KEK (key exchange key) according to RFC2631 which we use * to wrap the bulk encryption key. */ kek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE, ukm, NULL, /* XXXX */CKM_KEA_KEY_DERIVE, /* XXXX */CKM_SKIPJACK_WRAP, CKA_WRAP, 0, wincx); SECKEY_DestroyPublicKey(publickey); SECKEY_DestroyPrivateKey(ourPrivKey); publickey = NULL; ourPrivKey = NULL; if (!kek) goto loser; /* allocate space for the encrypted CEK (bulk key) */ encKey->data = (unsigned char*)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE); encKey->len = SMIME_FORTEZZA_MAX_KEY_SIZE; if (encKey->data == NULL) { PK11_FreeSymKey(kek); goto loser; } /* Wrap the bulk key using CMSRC2WRAP or CMS3DESWRAP, depending on the */ /* bulk encryption algorithm */ switch (/* XXXX */PK11_AlgtagToMechanism(enccinfo->encalg)) { case /* XXXX */CKM_SKIPJACK_CFB8: err = PK11_WrapSymKey(/* XXXX */CKM_CMS3DES_WRAP, NULL, kek, bulkkey, encKey); whichKEA = NSSCMSKEAUsesSkipjack; break; case /* XXXX */CKM_SKIPJACK_CFB8: err = PK11_WrapSymKey(/* XXXX */CKM_CMSRC2_WRAP, NULL, kek, bulkkey, encKey); whichKEA = NSSCMSKEAUsesSkipjack; break; default: /* XXXX what do we do here? Neither RC2 nor 3DES... */ err = SECFailure; /* set error */ break; } PK11_FreeSymKey(kek); /* we do not need the KEK anymore */ if (err != SECSuccess) goto loser; PORT_Assert(whichKEA != NSSCMSKEAInvalid); /* see RFC2630 12.3.1.1 "keyEncryptionAlgorithm must be ..." */ /* params is the DER encoded key wrap algorithm (with parameters!) (XXX) */ params = SEC_ASN1EncodeItem(arena, NULL, &keaParams, sec_pkcs7_get_kea_template(whichKEA)); if (params == NULL) goto loser; /* now set keyEncAlg */ rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN, params); if (rv != SECSuccess) goto loser; /* XXXXXXX this is not right yet */ loser: if (arena) { PORT_FreeArena(arena, PR_FALSE); } if (publickey) { SECKEY_DestroyPublicKey(publickey); } if (ourPrivKey) { SECKEY_DestroyPrivateKey(ourPrivKey); } #endif return SECFailure; }
static int SignFile(FILE *outFile, PRFileDesc *inFile, CERTCertificate *cert) { SECItem data2sign; SECStatus rv; char *data; SECKEYPrivateKey *privKey; SECOidTag algID; PLArenaPool *arena; CERTSignedData sd; SECItem *result; if (outFile == NULL || inFile == NULL || cert == NULL) return -1; /* suck the file in */ if (SECU_ReadDERFromFile(&data2sign, inFile, PR_FALSE, PR_FALSE) != SECSuccess) return -1; privKey = NULL; privKey = PK11_FindKeyByAnyCert(cert, NULL); algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, SEC_OID_SHA1); if (algID == SEC_OID_UNKNOWN) return -1; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); PORT_Memset(&sd, 0, sizeof(CERTSignedData)); rv = SEC_SignData(&(sd.signature), data2sign.data, data2sign.len, privKey, algID); if (rv != SECSuccess) { fprintf (stderr, "Could not sign.\n"); return -1; } sd.signature.len = sd.signature.len << 3; rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0); if (rv != SECSuccess) { fprintf (stderr, "Could not set alg id.\n"); return -1; } result = SEC_ASN1EncodeItem(arena, NULL, &sd, CERTSignatureDataTemplate); SECITEM_FreeItem(&(sd.signature), PR_FALSE); if (!result) { fprintf (stderr, "Could not encode.\n"); return -1; } data = PL_Base64Encode((const char*)result->data, result->len, NULL); if (!data) return -1; fputs("signature:\n", outFile); fputs(data, outFile); fputs("\n", outFile); ExportPublicKey(outFile, cert); SECKEY_DestroyPrivateKey(privKey); PORT_FreeArena(arena, PR_FALSE); return 0; }
/* turn a PKCS #11 parameter into a DER Encoded Algorithm ID */ SECStatus PK11_ParamToAlgid(SECOidTag algTag, SECItem *param, PRArenaPool *arena, SECAlgorithmID *algid) { CK_RC2_CBC_PARAMS *rc2_params; sec_rc2cbcParameter rc2; CK_RC5_CBC_PARAMS *rc5_params; sec_rc5cbcParameter rc5; CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(algTag); SECItem *newParams = NULL; SECStatus rv = SECFailure; unsigned long rc2version; switch (type) { case CKM_RC4: case CKM_SEED_ECB: case CKM_CAMELLIA_ECB: case CKM_AES_ECB: case CKM_DES_ECB: case CKM_DES3_ECB: case CKM_IDEA_ECB: case CKM_CDMF_ECB: case CKM_CAST_ECB: case CKM_CAST3_ECB: case CKM_CAST5_ECB: newParams = NULL; rv = SECSuccess; break; case CKM_RC2_ECB: break; case CKM_RC2_CBC: case CKM_RC2_CBC_PAD: rc2_params = (CK_RC2_CBC_PARAMS *)param->data; rc2version = rc2_unmap(rc2_params->ulEffectiveBits); if (SEC_ASN1EncodeUnsignedInteger (NULL, &(rc2.rc2ParameterVersion), rc2version) == NULL) break; rc2.iv.data = rc2_params->iv; rc2.iv.len = sizeof(rc2_params->iv); newParams = SEC_ASN1EncodeItem (NULL, NULL, &rc2, sec_rc2cbc_parameter_template); PORT_Free(rc2.rc2ParameterVersion.data); if (newParams == NULL) break; rv = SECSuccess; break; case CKM_RC5_ECB: /* well not really... */ break; case CKM_RC5_CBC: case CKM_RC5_CBC_PAD: rc5_params = (CK_RC5_CBC_PARAMS *)param->data; if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.version, RC5_V10) == NULL) break; if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.blockSizeInBits, rc5_params->ulWordsize*8) == NULL) { PORT_Free(rc5.version.data); break; } if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.rounds, rc5_params->ulWordsize*8) == NULL) { PORT_Free(rc5.blockSizeInBits.data); PORT_Free(rc5.version.data); break; } rc5.iv.data = rc5_params->pIv; rc5.iv.len = rc5_params->ulIvLen; newParams = SEC_ASN1EncodeItem (NULL, NULL, &rc5, sec_rc5cbc_parameter_template); PORT_Free(rc5.version.data); PORT_Free(rc5.blockSizeInBits.data); PORT_Free(rc5.rounds.data); if (newParams == NULL) break; rv = SECSuccess; break; case CKM_PBE_MD2_DES_CBC: case CKM_PBE_MD5_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: case CKM_PBE_SHA1_DES3_EDE_CBC: case CKM_PBE_SHA1_DES2_EDE_CBC: case CKM_PBE_SHA1_RC2_40_CBC: case CKM_PBE_SHA1_RC2_128_CBC: case CKM_PBE_SHA1_RC4_40: case CKM_PBE_SHA1_RC4_128: return PBE_PK11ParamToAlgid(algTag, param, arena, algid); default: if (pk11_lookup(type)->iv == 0) { rv = SECSuccess; newParams = NULL; break; } case CKM_SEED_CBC: case CKM_CAMELLIA_CBC: case CKM_AES_CBC: case CKM_DES_CBC: case CKM_DES3_CBC: case CKM_IDEA_CBC: case CKM_CDMF_CBC: case CKM_CAST_CBC: case CKM_CAST3_CBC: case CKM_CAST5_CBC: case CKM_DES_CBC_PAD: case CKM_DES3_CBC_PAD: case CKM_IDEA_CBC_PAD: case CKM_CDMF_CBC_PAD: case CKM_CAST_CBC_PAD: case CKM_CAST3_CBC_PAD: case CKM_CAST5_CBC_PAD: case CKM_SKIPJACK_CBC64: case CKM_SKIPJACK_ECB64: case CKM_SKIPJACK_OFB64: case CKM_SKIPJACK_CFB64: case CKM_SKIPJACK_CFB32: case CKM_SKIPJACK_CFB16: case CKM_SKIPJACK_CFB8: case CKM_BATON_ECB128: case CKM_BATON_ECB96: case CKM_BATON_CBC128: case CKM_BATON_COUNTER: case CKM_BATON_SHUFFLE: case CKM_JUNIPER_ECB128: case CKM_JUNIPER_CBC128: case CKM_JUNIPER_COUNTER: case CKM_JUNIPER_SHUFFLE: newParams = SEC_ASN1EncodeItem(NULL,NULL,param, SEC_ASN1_GET(SEC_OctetStringTemplate) ); if (newParams == NULL) break; rv = SECSuccess; break; } if (rv != SECSuccess) { if (newParams) SECITEM_FreeItem(newParams,PR_TRUE); return rv; } rv = SECOID_SetAlgorithmID(arena, algid, algTag, newParams); SECITEM_FreeItem(newParams,PR_TRUE); return rv; }
/* * The caller is responsible for freeing the return value by passing it to * SECKEY_DestroyPrivateKeyInfo(..., PR_TRUE). */ SECKEYPrivateKeyInfo * PK11_ExportPrivKeyInfo(SECKEYPrivateKey *pk, void *wincx) { /* PrivateKeyInfo version (always zero) */ const unsigned char pkiVersion = 0; /* RSAPrivateKey version (always zero) */ const unsigned char rsaVersion = 0; PLArenaPool *arena = NULL; SECKEYRawPrivateKey rawKey; SECKEYPrivateKeyInfo *pki; SECItem *encoded; SECStatus rv; if (pk->keyType != rsaKey) { PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); goto loser; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { goto loser; } memset(&rawKey, 0, sizeof(rawKey)); rawKey.keyType = pk->keyType; rawKey.u.rsa.version.type = siUnsignedInteger; rawKey.u.rsa.version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1); if (!rawKey.u.rsa.version.data) { goto loser; } rawKey.u.rsa.version.data[0] = rsaVersion; rawKey.u.rsa.version.len = 1; /* Read the component attributes of the private key */ prepare_rsa_priv_key_export_for_asn1(&rawKey); if (!ReadAttribute(pk, CKA_MODULUS, arena, &rawKey.u.rsa.modulus) || !ReadAttribute(pk, CKA_PUBLIC_EXPONENT, arena, &rawKey.u.rsa.publicExponent) || !ReadAttribute(pk, CKA_PRIVATE_EXPONENT, arena, &rawKey.u.rsa.privateExponent) || !ReadAttribute(pk, CKA_PRIME_1, arena, &rawKey.u.rsa.prime1) || !ReadAttribute(pk, CKA_PRIME_2, arena, &rawKey.u.rsa.prime2) || !ReadAttribute(pk, CKA_EXPONENT_1, arena, &rawKey.u.rsa.exponent1) || !ReadAttribute(pk, CKA_EXPONENT_2, arena, &rawKey.u.rsa.exponent2) || !ReadAttribute(pk, CKA_COEFFICIENT, arena, &rawKey.u.rsa.coefficient)) { goto loser; } pki = PORT_ArenaZNew(arena, SECKEYPrivateKeyInfo); if (!pki) { goto loser; } encoded = SEC_ASN1EncodeItem(arena, &pki->privateKey, &rawKey, SECKEY_RSAPrivateKeyExportTemplate); if (!encoded) { goto loser; } rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_PKCS1_RSA_ENCRYPTION, NULL); if (rv != SECSuccess) { goto loser; } pki->version.type = siUnsignedInteger; pki->version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1); if (!pki->version.data) { goto loser; } pki->version.data[0] = pkiVersion; pki->version.len = 1; pki->arena = arena; return pki; loser: if (arena) { PORT_FreeArena(arena, PR_TRUE); } return NULL; }
/* * SecCmsSignerInfoSign - sign something * */ OSStatus SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType) { SecCertificateRef cert; SecPrivateKeyRef privkey = NULL; SECOidTag digestalgtag; SECOidTag pubkAlgTag; CSSM_DATA signature = { 0 }; OSStatus rv; PLArenaPool *poolp, *tmppoolp = NULL; const SECAlgorithmID *algID; SECAlgorithmID freeAlgID; //CERTSubjectPublicKeyInfo *spki; PORT_Assert (digest != NULL); poolp = signerinfo->cmsg->poolp; switch (signerinfo->signerIdentifier.identifierType) { case SecCmsSignerIDIssuerSN: privkey = signerinfo->signingKey; signerinfo->signingKey = NULL; cert = signerinfo->cert; if (SecCertificateGetAlgorithmID(cert,&algID)) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); goto loser; } break; case SecCmsSignerIDSubjectKeyID: privkey = signerinfo->signingKey; signerinfo->signingKey = NULL; #if 0 spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey); SECKEY_DestroyPublicKey(signerinfo->pubKey); signerinfo->pubKey = NULL; SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm); SECKEY_DestroySubjectPublicKeyInfo(spki); algID = &freeAlgID; #else #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)) if (SecKeyGetAlgorithmID(signerinfo->pubKey,&algID)) { #else /* TBD: Unify this code. Currently, iOS has an incompatible * SecKeyGetAlgorithmID implementation. */ if (true) { #endif PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); goto loser; } CFRelease(signerinfo->pubKey); signerinfo->pubKey = NULL; #endif break; default: PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE); goto loser; } digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo); /* * XXX I think there should be a cert-level interface for this, * so that I do not have to know about subjectPublicKeyInfo... */ pubkAlgTag = SECOID_GetAlgorithmTag(algID); if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID) { SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE); } #if 0 // @@@ Not yet /* Fortezza MISSI have weird signature formats. * Map them to standard DSA formats */ pubkAlgTag = PK11_FortezzaMapSig(pubkAlgTag); #endif if (signerinfo->authAttr != NULL) { CSSM_DATA encoded_attrs; /* find and fill in the message digest attribute. */ rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr), SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE); if (rv != SECSuccess) goto loser; if (contentType != NULL) { /* if the caller wants us to, find and fill in the content type attribute. */ rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr), SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE); if (rv != SECSuccess) goto loser; } if ((tmppoolp = PORT_NewArena (1024)) == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } /* * Before encoding, reorder the attributes so that when they * are encoded, they will be conforming DER, which is required * to have a specific order and that is what must be used for * the hash/signature. We do this here, rather than building * it into EncodeAttributes, because we do not want to do * such reordering on incoming messages (which also uses * EncodeAttributes) or our old signatures (and other "broken" * implementations) will not verify. So, we want to guarantee * that we send out good DER encodings of attributes, but not * to expect to receive them. */ if (SecCmsAttributeArrayReorder(signerinfo->authAttr) != SECSuccess) goto loser; encoded_attrs.Data = NULL; encoded_attrs.Length = 0; if (SecCmsAttributeArrayEncode(tmppoolp, &(signerinfo->authAttr), &encoded_attrs) == NULL) goto loser; rv = SEC_SignData(&signature, encoded_attrs.Data, (int)encoded_attrs.Length, privkey, digestalgtag, pubkAlgTag); PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */ tmppoolp = 0; } else { rv = SGN_Digest(privkey, digestalgtag, pubkAlgTag, &signature, digest); } SECKEY_DestroyPrivateKey(privkey); privkey = NULL; if (rv != SECSuccess) goto loser; if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) != SECSuccess) goto loser; SECITEM_FreeItem(&signature, PR_FALSE); if(pubkAlgTag == SEC_OID_EC_PUBLIC_KEY) { /* * RFC 3278 section section 2.1.1 states that the signatureAlgorithm * field contains the full ecdsa-with-SHA1 OID, not plain old ecPublicKey * as would appear in other forms of signed datas. However Microsoft doesn't * do this, it puts ecPublicKey there, and if we put ecdsa-with-SHA1 there, * MS can't verify - presumably because it takes the digest of the digest * before feeding it to ECDSA. * We handle this with a preference; default if it's not there is * "Microsoft compatibility mode". */ if(!SecCmsMsEcdsaCompatMode()) { pubkAlgTag = SEC_OID_ECDSA_WithSHA1; } /* else violating the spec for compatibility */ } if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag, NULL) != SECSuccess) goto loser; return SECSuccess; loser: if (signature.Length != 0) SECITEM_FreeItem (&signature, PR_FALSE); if (privkey) SECKEY_DestroyPrivateKey(privkey); if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE); return SECFailure; } OSStatus SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef keychainOrArray, CFTypeRef policies, SecTrustRef *trustRef) { SecCertificateRef cert; CFAbsoluteTime stime; OSStatus rv; CSSM_DATA_PTR *otherCerts; if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, keychainOrArray)) == NULL) { dprintf("SecCmsSignerInfoVerifyCertificate: no signing cert\n"); signerinfo->verificationStatus = SecCmsVSSigningCertNotFound; return SECFailure; } /* * Get and convert the signing time; if available, it will be used * both on the cert verification and for importing the sender * email profile. */ CFTypeRef timeStampPolicies=SecPolicyCreateAppleTimeStampingAndRevocationPolicies(policies); if (SecCmsSignerInfoGetTimestampTimeWithPolicy(signerinfo, timeStampPolicies, &stime) != SECSuccess) if (SecCmsSignerInfoGetSigningTime(signerinfo, &stime) != SECSuccess) stime = CFAbsoluteTimeGetCurrent(); CFReleaseSafe(timeStampPolicies); rv = SecCmsSignedDataRawCerts(signerinfo->sigd, &otherCerts); if(rv) { return rv; } rv = CERT_VerifyCert(keychainOrArray, cert, otherCerts, policies, stime, trustRef); dprintfRC("SecCmsSignerInfoVerifyCertificate after vfy: certp %p cert.rc %d\n", cert, (int)CFGetRetainCount(cert)); if (rv || !trustRef) { if (PORT_GetError() == SEC_ERROR_UNTRUSTED_CERT) { /* Signature or digest level verificationStatus errors should supercede certificate level errors, so only change the verificationStatus if the status was GoodSignature. */ if (signerinfo->verificationStatus == SecCmsVSGoodSignature) signerinfo->verificationStatus = SecCmsVSSigningCertNotTrusted; } } /* FIXME isn't this leaking the cert? */ dprintf("SecCmsSignerInfoVerifyCertificate: CertVerify rtn %d\n", (int)rv); return rv; }
SecCmsSignerInfoRef nss_cmssignerinfo_create(SecCmsMessageRef cmsg, SecCmsSignerIDSelector type, SecCertificateRef cert, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag) { void *mark; SecCmsSignerInfoRef signerinfo; int version; PLArenaPool *poolp; poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); signerinfo = (SecCmsSignerInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsSignerInfo)); if (signerinfo == NULL) { PORT_ArenaRelease(poolp, mark); return NULL; } signerinfo->cmsg = cmsg; switch(type) { case SecCmsSignerIDIssuerSN: signerinfo->signerIdentifier.identifierType = SecCmsSignerIDIssuerSN; if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL) goto loser; if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) goto loser; dprintfRC("nss_cmssignerinfo_create: SecCmsSignerIDIssuerSN: cert.rc %d\n", (int)CFGetRetainCount(signerinfo->cert)); break; case SecCmsSignerIDSubjectKeyID: signerinfo->signerIdentifier.identifierType = SecCmsSignerIDSubjectKeyID; PORT_Assert(subjKeyID); if (!subjKeyID) goto loser; signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, CSSM_DATA); if (SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID, subjKeyID)) { goto loser; } signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey); if (!signerinfo->pubKey) goto loser; break; default: goto loser; } if (!signingKey) goto loser; signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey); if (!signerinfo->signingKey) goto loser; /* set version right now */ version = SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN; /* RFC2630 5.3 "version is the syntax version number. If the .... " */ if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID) version = SEC_CMS_SIGNER_INFO_VERSION_SUBJKEY; (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version); if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return signerinfo; loser: PORT_ArenaRelease(poolp, mark); return NULL; }
static sec_PKCS7CipherObject * sec_pkcs7_encoder_start_encrypt (SEC_PKCS7ContentInfo *cinfo, PK11SymKey *orig_bulkkey) { SECOidTag kind; sec_PKCS7CipherObject *encryptobj; SEC_PKCS7RecipientInfo **recipientinfos, *ri; SEC_PKCS7EncryptedContentInfo *enccinfo; SECKEYPublicKey *publickey = NULL; SECKEYPrivateKey *ourPrivKey = NULL; PK11SymKey *bulkkey; void *mark, *wincx; int i; PLArenaPool *arena = NULL; /* Get the context in case we need it below. */ wincx = cinfo->pwfn_arg; kind = SEC_PKCS7ContentType (cinfo); switch (kind) { default: case SEC_OID_PKCS7_DATA: case SEC_OID_PKCS7_DIGESTED_DATA: case SEC_OID_PKCS7_SIGNED_DATA: recipientinfos = NULL; enccinfo = NULL; break; case SEC_OID_PKCS7_ENCRYPTED_DATA: { SEC_PKCS7EncryptedData *encdp; /* To do EncryptedData we *must* be given a bulk key. */ PORT_Assert (orig_bulkkey != NULL); if (orig_bulkkey == NULL) { /* XXX error? */ return NULL; } encdp = cinfo->content.encryptedData; recipientinfos = NULL; enccinfo = &(encdp->encContentInfo); } break; case SEC_OID_PKCS7_ENVELOPED_DATA: { SEC_PKCS7EnvelopedData *envdp; envdp = cinfo->content.envelopedData; recipientinfos = envdp->recipientInfos; enccinfo = &(envdp->encContentInfo); } break; case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: { SEC_PKCS7SignedAndEnvelopedData *saedp; saedp = cinfo->content.signedAndEnvelopedData; recipientinfos = saedp->recipientInfos; enccinfo = &(saedp->encContentInfo); } break; } if (enccinfo == NULL) return NULL; bulkkey = orig_bulkkey; if (bulkkey == NULL) { CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg); PK11SlotInfo *slot; slot = PK11_GetBestSlot(type,cinfo->pwfn_arg); if (slot == NULL) { return NULL; } bulkkey = PK11_KeyGen(slot,type,NULL, enccinfo->keysize/8, cinfo->pwfn_arg); PK11_FreeSlot(slot); if (bulkkey == NULL) { return NULL; } } encryptobj = NULL; mark = PORT_ArenaMark (cinfo->poolp); /* * Encrypt the bulk key with the public key of each recipient. */ for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL; i++) { CERTCertificate *cert; SECOidTag certalgtag, encalgtag; SECStatus rv; int data_len; SECItem *params = NULL; cert = ri->cert; PORT_Assert (cert != NULL); if (cert == NULL) continue; /* * XXX Want an interface that takes a cert and some data and * fills in an algorithmID and encrypts the data with the public * key from the cert. Or, give me two interfaces -- one which * gets the algorithm tag from a cert (I should not have to go * down into the subjectPublicKeyInfo myself) and another which * takes a public key and algorithm tag and data and encrypts * the data. Or something like that. The point is that all * of the following hardwired RSA stuff should be done elsewhere. */ certalgtag=SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: encalgtag = certalgtag; publickey = CERT_ExtractPublicKey (cert); if (publickey == NULL) goto loser; data_len = SECKEY_PublicKeyStrength(publickey); ri->encKey.data = (unsigned char*)PORT_ArenaAlloc(cinfo->poolp ,data_len); ri->encKey.len = data_len; if (ri->encKey.data == NULL) goto loser; rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag),publickey, bulkkey,&ri->encKey); SECKEY_DestroyPublicKey(publickey); publickey = NULL; if (rv != SECSuccess) goto loser; params = NULL; /* paranoia */ break; default: PORT_SetError (SEC_ERROR_INVALID_ALGORITHM); goto loser; } rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag, params); if (rv != SECSuccess) goto loser; if (arena) PORT_FreeArena(arena,PR_FALSE); arena = NULL; } encryptobj = sec_PKCS7CreateEncryptObject (cinfo->poolp, bulkkey, enccinfo->encalg, &(enccinfo->contentEncAlg)); if (encryptobj != NULL) { PORT_ArenaUnmark (cinfo->poolp, mark); mark = NULL; /* good one; do not want to release */ } /* fallthru */ loser: if (arena) { PORT_FreeArena(arena, PR_FALSE); } if (publickey) { SECKEY_DestroyPublicKey(publickey); } if (ourPrivKey) { SECKEY_DestroyPrivateKey(ourPrivKey); } if (mark != NULL) { PORT_ArenaRelease (cinfo->poolp, mark); } if (orig_bulkkey == NULL) { if (bulkkey) PK11_FreeSymKey(bulkkey); } return encryptobj; }
NSSCMSSignerInfo * nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type, CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey, SECKEYPrivateKey *signingKey, SECOidTag digestalgtag) { void *mark; NSSCMSSignerInfo *signerinfo; int version; PLArenaPool *poolp; poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo)); if (signerinfo == NULL) { PORT_ArenaRelease(poolp, mark); return NULL; } signerinfo->cmsg = cmsg; switch(type) { case NSSCMSSignerID_IssuerSN: signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_IssuerSN; if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL) goto loser; if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) goto loser; break; case NSSCMSSignerID_SubjectKeyID: signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_SubjectKeyID; PORT_Assert(subjKeyID); if (!subjKeyID) goto loser; signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, SECItem); SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID, subjKeyID); signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey); if (!signerinfo->signingKey) goto loser; signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey); if (!signerinfo->pubKey) goto loser; break; default: goto loser; } /* set version right now */ version = NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN; /* RFC2630 5.3 "version is the syntax version number. If the .... " */ if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID) version = NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY; (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version); if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return signerinfo; loser: PORT_ArenaRelease(poolp, mark); return NULL; }
SECStatus NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, SECOidTag bulkalgtag) { CERTCertificate *cert; SECOidTag certalgtag; SECStatus rv = SECSuccess; NSSCMSRecipientEncryptedKey *rek; NSSCMSOriginatorIdentifierOrKey *oiok; CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL; PLArenaPool *poolp; NSSCMSKeyTransRecipientInfoEx *extra = NULL; PRBool usesSubjKeyID; poolp = ri->cmsg->poolp; cert = ri->cert; usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); if (cert) { spki = &cert->subjectPublicKeyInfo; } else if (usesSubjKeyID) { extra = &ri->ri.keyTransRecipientInfoEx; /* sanity check */ PORT_Assert(extra->pubKey); if (!extra->pubKey) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey); } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* XXX set ri->recipientInfoType to the proper value here */ /* or should we look if it's been set already ? */ certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm); switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: /* wrap the symkey */ if (cert) { rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } else if (usesSubjKeyID) { PORT_Assert(extra != NULL); rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; if (rek == NULL) { rv = SECFailure; break; } oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey); /* see RFC2630 12.3.1.1 */ if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) { rv = SECFailure; break; } /* this will generate a key pair, compute the shared secret, */ /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ rv = NSS_CMSUtil_EncryptSymKey_ESDH(poolp, cert, bulkkey, &rek->encKey, &ri->ri.keyAgreeRecipientInfo.ukm, &ri->ri.keyAgreeRecipientInfo.keyEncAlg, &oiok->id.originatorPublicKey.publicKey); break; default: /* other algorithms not supported yet */ /* NOTE that we do not support any KEK algorithm */ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); rv = SECFailure; } if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); return rv; }
OSStatus SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey, SECOidTag bulkalgtag) { SecCertificateRef cert; SECOidTag certalgtag; OSStatus rv = SECSuccess; #if 0 CSSM_DATA_PTR params = NULL; #endif /* 0 */ SecCmsRecipientEncryptedKey *rek; SecCmsOriginatorIdentifierOrKey *oiok; const SECAlgorithmID *algid; PLArenaPool *poolp; SecCmsKeyTransRecipientInfoEx *extra = NULL; Boolean usesSubjKeyID; uint8 nullData[2] = {SEC_ASN1_NULL, 0}; SECItem nullItem; SecCmsKeyAgreeRecipientInfo *kari; poolp = ri->cmsg->poolp; cert = ri->cert; usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); if (cert) { rv = SecCertificateGetAlgorithmID(cert,&algid); if (rv) return SECFailure; certalgtag = SECOID_GetAlgorithmTag(algid); } else if (usesSubjKeyID) { extra = &ri->ri.keyTransRecipientInfoEx; /* sanity check */ PORT_Assert(extra->pubKey); if (!extra->pubKey) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } rv = SecKeyGetAlgorithmID(extra->pubKey,&algid); if (rv) return SECFailure; certalgtag = SECOID_GetAlgorithmTag(algid); } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* XXX set ri->recipientInfoType to the proper value here */ /* or should we look if it's been set already ? */ certalgtag = SECOID_GetAlgorithmTag(algid); switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: /* wrap the symkey */ if (cert) { rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } else if (usesSubjKeyID) { PORT_Assert(extra != NULL); rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); break; #if 0 case SEC_OID_MISSI_KEA_DSS_OLD: case SEC_OID_MISSI_KEA_DSS: case SEC_OID_MISSI_KEA: rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey, bulkalgtag, &ri->ri.keyTransRecipientInfo.encKey, ¶ms, ri->cmsg->pwfn_arg); if (rv != SECSuccess) break; /* here, we DO need to pass the params to the wrap function because, with * RSA, there is no funny stuff going on with generation of IV vectors or so */ rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params); break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; if (rek == NULL) { rv = SECFailure; break; } oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey); /* see RFC2630 12.3.1.1 */ if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) { rv = SECFailure; break; } /* this will generate a key pair, compute the shared secret, */ /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey, &rek->encKey, &ri->ri.keyAgreeRecipientInfo.ukm, &ri->ri.keyAgreeRecipientInfo.keyEncAlg, &oiok->id.originatorPublicKey.publicKey); break; #endif /* 0 */ case SEC_OID_EC_PUBLIC_KEY: /* These were set up in nss_cmsrecipientinfo_create() */ kari = &ri->ri.keyAgreeRecipientInfo; rek = kari->recipientEncryptedKeys[0]; if (rek == NULL) { rv = SECFailure; break; } oiok = &(kari->originatorIdentifierOrKey); PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey); /* * RFC 3278 3.1.1 says this AlgId must contain NULL params which is contrary to * any other use of the SEC_OID_EC_PUBLIC_KEY OID. So we provide one * explicitly instead of mucking up the login in SECOID_SetAlgorithmID(). */ nullItem.Data = nullData; nullItem.Length = 2; if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, SEC_OID_EC_PUBLIC_KEY, &nullItem) != SECSuccess) { rv = SECFailure; break; } /* this will generate a key pair, compute the shared secret, */ /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ rv = SecCmsUtilEncryptSymKeyECDH(poolp, cert, bulkkey, &rek->encKey, &kari->ukm, &kari->keyEncAlg, &oiok->id.originatorPublicKey.publicKey); /* this is a BIT STRING */ oiok->id.originatorPublicKey.publicKey.Length <<= 3; break; default: /* other algorithms not supported yet */ /* NOTE that we do not support any KEK algorithm */ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); rv = SECFailure; break; } #if 0 if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); #endif return rv; }
static SECItem * sec_CreateRSAPSSParameters(PLArenaPool *arena, SECItem *result, SECOidTag hashAlgTag, const SECItem *params, const SECKEYPrivateKey *key) { SECKEYRSAPSSParams pssParams; int modBytes, hashLength; unsigned long saltLength; PRBool defaultSHA1 = PR_FALSE; SECStatus rv; if (key->keyType != rsaKey && key->keyType != rsaPssKey) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } PORT_Memset(&pssParams, 0, sizeof(pssParams)); if (params && params->data) { /* The parameters field should either be empty or contain * valid RSA-PSS parameters */ PORT_Assert(!(params->len == 2 && params->data[0] == SEC_ASN1_NULL && params->data[1] == 0)); rv = SEC_QuickDERDecodeItem(arena, &pssParams, SECKEY_RSAPSSParamsTemplate, params); if (rv != SECSuccess) { return NULL; } defaultSHA1 = PR_TRUE; } if (pssParams.trailerField.data) { unsigned long trailerField; rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.trailerField, &trailerField); if (rv != SECSuccess) { return NULL; } if (trailerField != 1) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } } modBytes = PK11_GetPrivateModulusLen((SECKEYPrivateKey *)key); /* Determine the hash algorithm to use, based on hashAlgTag and * pssParams.hashAlg; there are four cases */ if (hashAlgTag != SEC_OID_UNKNOWN) { SECOidTag tag = SEC_OID_UNKNOWN; if (pssParams.hashAlg) { tag = SECOID_GetAlgorithmTag(pssParams.hashAlg); } else if (defaultSHA1) { tag = SEC_OID_SHA1; } if (tag != SEC_OID_UNKNOWN && tag != hashAlgTag) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } } else if (hashAlgTag == SEC_OID_UNKNOWN) { if (pssParams.hashAlg) { hashAlgTag = SECOID_GetAlgorithmTag(pssParams.hashAlg); } else if (defaultSHA1) { hashAlgTag = SEC_OID_SHA1; } else { /* Find a suitable hash algorithm based on the NIST recommendation */ if (modBytes <= 384) { /* 128, in NIST 800-57, Part 1 */ hashAlgTag = SEC_OID_SHA256; } else if (modBytes <= 960) { /* 192, NIST 800-57, Part 1 */ hashAlgTag = SEC_OID_SHA384; } else { hashAlgTag = SEC_OID_SHA512; } } } if (hashAlgTag != SEC_OID_SHA1 && hashAlgTag != SEC_OID_SHA224 && hashAlgTag != SEC_OID_SHA256 && hashAlgTag != SEC_OID_SHA384 && hashAlgTag != SEC_OID_SHA512) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } /* Now that the hash algorithm is decided, check if it matches the * existing parameters if any */ if (pssParams.maskAlg) { SECAlgorithmID maskHashAlg; if (SECOID_GetAlgorithmTag(pssParams.maskAlg) != SEC_OID_PKCS1_MGF1) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } if (pssParams.maskAlg->parameters.data == NULL) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } PORT_Memset(&maskHashAlg, 0, sizeof(maskHashAlg)); rv = SEC_QuickDERDecodeItem(arena, &maskHashAlg, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), &pssParams.maskAlg->parameters); if (rv != SECSuccess) { return NULL; } /* Following the recommendation in RFC 4055, assume the hash * algorithm identical to pssParam.hashAlg */ if (SECOID_GetAlgorithmTag(&maskHashAlg) != hashAlgTag) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } } else if (defaultSHA1) { if (hashAlgTag != SEC_OID_SHA1) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } } hashLength = HASH_ResultLenByOidTag(hashAlgTag); if (pssParams.saltLength.data) { rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.saltLength, &saltLength); if (rv != SECSuccess) { return NULL; } /* The specified salt length is too long */ if (saltLength > modBytes - hashLength - 2) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } } else if (defaultSHA1) { saltLength = 20; } /* Fill in the parameters */ if (pssParams.hashAlg) { if (hashAlgTag == SEC_OID_SHA1) { /* Omit hashAlg if the the algorithm is SHA-1 (default) */ pssParams.hashAlg = NULL; } } else { if (hashAlgTag != SEC_OID_SHA1) { pssParams.hashAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID)); if (!pssParams.hashAlg) { return NULL; } rv = SECOID_SetAlgorithmID(arena, pssParams.hashAlg, hashAlgTag, NULL); if (rv != SECSuccess) { return NULL; } } } if (pssParams.maskAlg) { if (hashAlgTag == SEC_OID_SHA1) { /* Omit maskAlg if the the algorithm is SHA-1 (default) */ pssParams.maskAlg = NULL; } } else { if (hashAlgTag != SEC_OID_SHA1) { SECItem *hashAlgItem; PORT_Assert(pssParams.hashAlg != NULL); hashAlgItem = SEC_ASN1EncodeItem(arena, NULL, pssParams.hashAlg, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate)); if (!hashAlgItem) { return NULL; } pssParams.maskAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID)); if (!pssParams.maskAlg) { return NULL; } rv = SECOID_SetAlgorithmID(arena, pssParams.maskAlg, SEC_OID_PKCS1_MGF1, hashAlgItem); if (rv != SECSuccess) { return NULL; } } } if (pssParams.saltLength.data) { if (saltLength == 20) { /* Omit the salt length if it is the default */ pssParams.saltLength.data = NULL; } } else { /* Find a suitable length from the hash algorithm and modulus bits */ saltLength = PR_MIN(hashLength, modBytes - hashLength - 2); if (saltLength != 20 && !SEC_ASN1EncodeInteger(arena, &pssParams.saltLength, saltLength)) { return NULL; } } if (pssParams.trailerField.data) { /* Omit trailerField if the value is 1 (default) */ pssParams.trailerField.data = NULL; } return SEC_ASN1EncodeItem(arena, result, &pssParams, SECKEY_RSAPSSParamsTemplate); }
OSStatus SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey, SECOidTag bulkalgtag) { SecCertificateRef cert; SECOidTag certalgtag; OSStatus rv = SECSuccess; #if 0 SecAsn1Item * params = NULL; SecCmsRecipientEncryptedKey *rek; SecCmsOriginatorIdentifierOrKey *oiok; #endif /* 0 */ const SECAlgorithmID *algid; PLArenaPool *poolp; SecCmsKeyTransRecipientInfoEx *extra = NULL; Boolean usesSubjKeyID; poolp = ri->envelopedData->contentInfo.cmsg->poolp; cert = ri->cert; usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); if (cert) { #if USE_CDSA_CRYPTO rv = SecCertificateGetAlgorithmID(cert,&algid); if (rv) return SECFailure; #else SECAlgorithmID freeAlgID; const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert); freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data; freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length; freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data; freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length; algid = &freeAlgID; #endif } else if (usesSubjKeyID) { extra = &ri->ri.keyTransRecipientInfoEx; /* sanity check */ PORT_Assert(extra->pubKey); if (!extra->pubKey) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } #if USE_CDSA_CRYPTO rv = SecKeyGetAlgorithmID(extra->pubKey,&algid); if (rv) #endif return SECFailure; certalgtag = SECOID_GetAlgorithmTag(algid); } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* XXX set ri->recipientInfoType to the proper value here */ /* or should we look if it's been set already ? */ certalgtag = SECOID_GetAlgorithmTag(algid); switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: /* wrap the symkey */ if (cert) { rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } else if (usesSubjKeyID) { PORT_Assert(extra != NULL); rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); break; #if 0 case SEC_OID_MISSI_KEA_DSS_OLD: case SEC_OID_MISSI_KEA_DSS: case SEC_OID_MISSI_KEA: rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey, bulkalgtag, &ri->ri.keyTransRecipientInfo.encKey, ¶ms, ri->cmsg->pwfn_arg); if (rv != SECSuccess) break; /* here, we DO need to pass the params to the wrap function because, with * RSA, there is no funny stuff going on with generation of IV vectors or so */ rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params); break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; if (rek == NULL) { rv = SECFailure; break; } oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey); /* see RFC2630 12.3.1.1 */ if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) { rv = SECFailure; break; } /* this will generate a key pair, compute the shared secret, */ /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey, &rek->encKey, &ri->ri.keyAgreeRecipientInfo.ukm, &ri->ri.keyAgreeRecipientInfo.keyEncAlg, &oiok->id.originatorPublicKey.publicKey); break; #endif /* 0 */ default: /* other algorithms not supported yet */ /* NOTE that we do not support any KEK algorithm */ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); rv = SECFailure; break; } #if 0 if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); #endif return rv; }
nsresult Generate() { nsresult rv; // Get the key slot for generation later UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); if (!slot) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Remove existing certs with this name (if any) rv = RemoveExisting(); if (NS_FAILED(rv)) { return rv; } // Generate a new cert NS_NAMED_LITERAL_CSTRING(commonNamePrefix, "CN="); nsAutoCString subjectNameStr(commonNamePrefix + mNickname); UniqueCERTName subjectName(CERT_AsciiToName(subjectNameStr.get())); if (!subjectName) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Use the well-known NIST P-256 curve SECOidData* curveOidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); if (!curveOidData) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Get key params from the curve ScopedAutoSECItem keyParams(2 + curveOidData->oid.len); keyParams.data[0] = SEC_ASN1_OBJECT_ID; keyParams.data[1] = curveOidData->oid.len; memcpy(keyParams.data + 2, curveOidData->oid.data, curveOidData->oid.len); // Generate cert key pair SECKEYPublicKey* tempPublicKey; UniqueSECKEYPrivateKey privateKey( PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &keyParams, &tempPublicKey, true /* token */, true /* sensitive */, nullptr)); UniqueSECKEYPublicKey publicKey(tempPublicKey); tempPublicKey = nullptr; if (!privateKey || !publicKey) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Create subject public key info and cert request UniqueCERTSubjectPublicKeyInfo spki( SECKEY_CreateSubjectPublicKeyInfo(publicKey.get())); if (!spki) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } UniqueCERTCertificateRequest certRequest( CERT_CreateCertificateRequest(subjectName.get(), spki.get(), nullptr)); if (!certRequest) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Valid from one day before to 1 year after static const PRTime oneDay = PRTime(PR_USEC_PER_SEC) * PRTime(60) // sec * PRTime(60) // min * PRTime(24); // hours PRTime now = PR_Now(); PRTime notBefore = now - oneDay; PRTime notAfter = now + (PRTime(365) * oneDay); UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter)); if (!validity) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Generate random serial unsigned long serial; // This serial in principle could collide, but it's unlikely rv = MapSECStatus(PK11_GenerateRandomOnSlot( slot.get(), BitwiseCast<unsigned char*, unsigned long*>(&serial), sizeof(serial))); if (NS_FAILED(rv)) { return rv; } // Create the cert from these pieces UniqueCERTCertificate cert( CERT_CreateCertificate(serial, subjectName.get(), validity.get(), certRequest.get())); if (!cert) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Update the cert version to X509v3 if (!cert->version.data) { return NS_ERROR_INVALID_POINTER; } *(cert->version.data) = SEC_CERTIFICATE_VERSION_3; cert->version.len = 1; // Set cert signature algorithm PLArenaPool* arena = cert->arena; if (!arena) { return NS_ERROR_INVALID_POINTER; } rv = MapSECStatus( SECOID_SetAlgorithmID(arena, &cert->signature, SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, 0)); if (NS_FAILED(rv)) { return rv; } // Encode and self-sign the cert UniqueSECItem certDER( SEC_ASN1EncodeItem(nullptr, nullptr, cert.get(), SEC_ASN1_GET(CERT_CertificateTemplate))); if (!certDER) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } rv = MapSECStatus( SEC_DerSignData(arena, &cert->derCert, certDER->data, certDER->len, privateKey.get(), SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE)); if (NS_FAILED(rv)) { return rv; } // Create a CERTCertificate from the signed data UniqueCERTCertificate certFromDER( CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &cert->derCert, nullptr, true /* perm */, true /* copyDER */)); if (!certFromDER) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // Save the cert in the DB rv = MapSECStatus(PK11_ImportCert(slot.get(), certFromDER.get(), CK_INVALID_HANDLE, mNickname.get(), false /* unused */)); if (NS_FAILED(rv)) { return rv; } // We should now have cert in the DB, read it back in nsIX509Cert form return GetFromDB(); }
SGNDigestInfo * SGN_CreateDigestInfo(SECOidTag algorithm, const unsigned char *sig, unsigned len) { SGNDigestInfo *di; SECStatus rv; PLArenaPool *arena; SECItem *null_param; SECItem dummy_value; switch (algorithm) { case SEC_OID_MD2: case SEC_OID_MD5: case SEC_OID_SHA1: case SEC_OID_SHA224: case SEC_OID_SHA256: case SEC_OID_SHA384: case SEC_OID_SHA512: break; default: PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { return NULL; } di = (SGNDigestInfo *) PORT_ArenaZAlloc(arena, sizeof(SGNDigestInfo)); if (di == NULL) { PORT_FreeArena(arena, PR_FALSE); return NULL; } di->arena = arena; /* * PKCS #1 specifies that the AlgorithmID must have a NULL parameter * (as opposed to no parameter at all). */ dummy_value.data = NULL; dummy_value.len = 0; null_param = SEC_ASN1EncodeItem(NULL, NULL, &dummy_value, SEC_NullTemplate); if (null_param == NULL) { goto loser; } rv = SECOID_SetAlgorithmID(arena, &di->digestAlgorithm, algorithm, null_param); SECITEM_FreeItem(null_param, PR_TRUE); if (rv != SECSuccess) { goto loser; } di->digest.data = (unsigned char *) PORT_ArenaAlloc(arena, len); if (di->digest.data == NULL) { goto loser; } di->digest.len = len; PORT_Memcpy(di->digest.data, sig, len); return di; loser: SGN_DestroyDigestInfo(di); return NULL; }
CRMFEncryptedValue * crmf_create_encrypted_value_wrapped_privkey(SECKEYPrivateKey *inPrivKey, SECKEYPublicKey *inCAKey, CRMFEncryptedValue *destValue) { SECItem wrappedPrivKey, wrappedSymKey; SECItem encodedParam, *dummy; SECStatus rv; CK_MECHANISM_TYPE pubMechType, symKeyType; unsigned char *wrappedSymKeyBits; unsigned char *wrappedPrivKeyBits; SECItem *iv = NULL; SECOidTag tag; PK11SymKey *symKey; PK11SlotInfo *slot; SECAlgorithmID *symmAlg; CRMFEncryptedValue *myEncrValue = NULL; encodedParam.data = NULL; wrappedSymKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN); wrappedPrivKeyBits = PORT_NewArray(unsigned char, MAX_WRAPPED_KEY_LEN); if (wrappedSymKeyBits == NULL || wrappedPrivKeyBits == NULL) { goto loser; } if (destValue == NULL) { myEncrValue = destValue = PORT_ZNew(CRMFEncryptedValue); if (destValue == NULL) { goto loser; } } pubMechType = crmf_get_mechanism_from_public_key(inCAKey); if (pubMechType == CKM_INVALID_MECHANISM) { /* XXX I should probably do something here for non-RSA * keys that are in certs. (ie DSA) * XXX or at least SET AN ERROR CODE. */ goto loser; } slot = inPrivKey->pkcs11Slot; PORT_Assert(slot != NULL); symKeyType = crmf_get_best_privkey_wrap_mechanism(slot); symKey = PK11_KeyGen(slot, symKeyType, NULL, 0, NULL); if (symKey == NULL) { goto loser; } wrappedSymKey.data = wrappedSymKeyBits; wrappedSymKey.len = MAX_WRAPPED_KEY_LEN; rv = PK11_PubWrapSymKey(pubMechType, inCAKey, symKey, &wrappedSymKey); if (rv != SECSuccess) { goto loser; } /* Make the length of the result a Bit String length. */ wrappedSymKey.len <<= 3; wrappedPrivKey.data = wrappedPrivKeyBits; wrappedPrivKey.len = MAX_WRAPPED_KEY_LEN; iv = crmf_get_iv(symKeyType); rv = PK11_WrapPrivKey(slot, symKey, inPrivKey, symKeyType, iv, &wrappedPrivKey, NULL); PK11_FreeSymKey(symKey); if (rv != SECSuccess) { goto loser; } /* Make the length of the result a Bit String length. */ wrappedPrivKey.len <<= 3; rv = crmf_make_bitstring_copy(NULL, &destValue->encValue, &wrappedPrivKey); if (rv != SECSuccess) { goto loser; } rv = crmf_make_bitstring_copy(NULL, &destValue->encSymmKey, &wrappedSymKey); if (rv != SECSuccess) { goto loser; } destValue->symmAlg = symmAlg = PORT_ZNew(SECAlgorithmID); if (symmAlg == NULL) { goto loser; } dummy = SEC_ASN1EncodeItem(NULL, &encodedParam, iv, SEC_ASN1_GET(SEC_OctetStringTemplate)); if (dummy != &encodedParam) { SECITEM_FreeItem(dummy, PR_TRUE); goto loser; } symKeyType = crmf_get_non_pad_mechanism(symKeyType); tag = PK11_MechanismToAlgtag(symKeyType); rv = SECOID_SetAlgorithmID(NULL, symmAlg, tag, &encodedParam); if (rv != SECSuccess) { goto loser; } SECITEM_FreeItem(&encodedParam, PR_FALSE); PORT_Free(wrappedPrivKeyBits); PORT_Free(wrappedSymKeyBits); SECITEM_FreeItem(iv, PR_TRUE); return destValue; loser: if (iv != NULL) { SECITEM_FreeItem(iv, PR_TRUE); } if (myEncrValue != NULL) { crmf_destroy_encrypted_value(myEncrValue, PR_TRUE); } if (wrappedSymKeyBits != NULL) { PORT_Free(wrappedSymKeyBits); } if (wrappedPrivKeyBits != NULL) { PORT_Free(wrappedPrivKeyBits); } if (encodedParam.data != NULL) { SECITEM_FreeItem(&encodedParam, PR_FALSE); } return NULL; }
/* * NSS_CMSSignerInfo_Sign - sign something * */ SECStatus NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest, SECItem *contentType) { CERTCertificate *cert; SECKEYPrivateKey *privkey = NULL; SECOidTag digestalgtag; SECOidTag pubkAlgTag; SECItem signature = { 0 }; SECStatus rv; PLArenaPool *poolp, *tmppoolp = NULL; SECAlgorithmID *algID, freeAlgID; CERTSubjectPublicKeyInfo *spki; PORT_Assert (digest != NULL); poolp = signerinfo->cmsg->poolp; switch (signerinfo->signerIdentifier.identifierType) { case NSSCMSSignerID_IssuerSN: cert = signerinfo->cert; privkey = PK11_FindKeyByAnyCert(cert, signerinfo->cmsg->pwfn_arg); if (privkey == NULL) goto loser; algID = &cert->subjectPublicKeyInfo.algorithm; break; case NSSCMSSignerID_SubjectKeyID: privkey = signerinfo->signingKey; signerinfo->signingKey = NULL; spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey); SECKEY_DestroyPublicKey(signerinfo->pubKey); signerinfo->pubKey = NULL; SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm); SECKEY_DestroySubjectPublicKeyInfo(spki); algID = &freeAlgID; break; default: goto loser; } digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo); /* * XXX I think there should be a cert-level interface for this, * so that I do not have to know about subjectPublicKeyInfo... */ pubkAlgTag = SECOID_GetAlgorithmTag(algID); if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID) { SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE); } if (signerinfo->authAttr != NULL) { SECOidTag signAlgTag; SECItem encoded_attrs; /* find and fill in the message digest attribute. */ rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr), SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE); if (rv != SECSuccess) goto loser; if (contentType != NULL) { /* if the caller wants us to, find and fill in the content type attribute. */ rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr), SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE); if (rv != SECSuccess) goto loser; } if ((tmppoolp = PORT_NewArena (1024)) == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } /* * Before encoding, reorder the attributes so that when they * are encoded, they will be conforming DER, which is required * to have a specific order and that is what must be used for * the hash/signature. We do this here, rather than building * it into EncodeAttributes, because we do not want to do * such reordering on incoming messages (which also uses * EncodeAttributes) or our old signatures (and other "broken" * implementations) will not verify. So, we want to guarantee * that we send out good DER encodings of attributes, but not * to expect to receive them. */ if (NSS_CMSAttributeArray_Reorder(signerinfo->authAttr) != SECSuccess) goto loser; encoded_attrs.data = NULL; encoded_attrs.len = 0; if (NSS_CMSAttributeArray_Encode(tmppoolp, &(signerinfo->authAttr), &encoded_attrs) == NULL) goto loser; signAlgTag = SEC_GetSignatureAlgorithmOidTag(privkey->keyType, digestalgtag); if (signAlgTag == SEC_OID_UNKNOWN) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); goto loser; } rv = SEC_SignData(&signature, encoded_attrs.data, encoded_attrs.len, privkey, signAlgTag); PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */ tmppoolp = 0; } else { rv = SGN_Digest(privkey, digestalgtag, &signature, digest); } SECKEY_DestroyPrivateKey(privkey); privkey = NULL; if (rv != SECSuccess) goto loser; if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) != SECSuccess) goto loser; SECITEM_FreeItem(&signature, PR_FALSE); if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag, NULL) != SECSuccess) goto loser; return SECSuccess; loser: if (signature.len != 0) SECITEM_FreeItem (&signature, PR_FALSE); if (privkey) SECKEY_DestroyPrivateKey(privkey); if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE); return SECFailure; }
RefPtr<DtlsIdentity> DtlsIdentity::Generate() { UniquePK11SlotInfo slot(PK11_GetInternalSlot()); if (!slot) { return nullptr; } uint8_t random_name[16]; SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), random_name, sizeof(random_name)); if (rv != SECSuccess) return nullptr; std::string name; char chunk[3]; for (size_t i = 0; i < sizeof(random_name); ++i) { SprintfLiteral(chunk, "%.2x", random_name[i]); name += chunk; } std::string subject_name_string = "CN=" + name; UniqueCERTName subject_name(CERT_AsciiToName(subject_name_string.c_str())); if (!subject_name) { return nullptr; } unsigned char paramBuf[12]; // OIDs are small SECItem ecdsaParams = { siBuffer, paramBuf, sizeof(paramBuf) }; SECOidData* oidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); if (!oidData || (oidData->oid.len > (sizeof(paramBuf) - 2))) { return nullptr; } ecdsaParams.data[0] = SEC_ASN1_OBJECT_ID; ecdsaParams.data[1] = oidData->oid.len; memcpy(ecdsaParams.data + 2, oidData->oid.data, oidData->oid.len); ecdsaParams.len = oidData->oid.len + 2; SECKEYPublicKey *pubkey; UniqueSECKEYPrivateKey private_key( PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &ecdsaParams, &pubkey, PR_FALSE, PR_TRUE, nullptr)); if (private_key == nullptr) return nullptr; UniqueSECKEYPublicKey public_key(pubkey); pubkey = nullptr; UniqueCERTSubjectPublicKeyInfo spki( SECKEY_CreateSubjectPublicKeyInfo(public_key.get())); if (!spki) { return nullptr; } UniqueCERTCertificateRequest certreq( CERT_CreateCertificateRequest(subject_name.get(), spki.get(), nullptr)); if (!certreq) { return nullptr; } // From 1 day before todayto 30 days after. // This is a sort of arbitrary range designed to be valid // now with some slack in case the other side expects // some before expiry. // // Note: explicit casts necessary to avoid // warning C4307: '*' : integral constant overflow static const PRTime oneDay = PRTime(PR_USEC_PER_SEC) * PRTime(60) // sec * PRTime(60) // min * PRTime(24); // hours PRTime now = PR_Now(); PRTime notBefore = now - oneDay; PRTime notAfter = now + (PRTime(30) * oneDay); UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter)); if (!validity) { return nullptr; } unsigned long serial; // Note: This serial in principle could collide, but it's unlikely rv = PK11_GenerateRandomOnSlot(slot.get(), reinterpret_cast<unsigned char *>(&serial), sizeof(serial)); if (rv != SECSuccess) { return nullptr; } UniqueCERTCertificate certificate( CERT_CreateCertificate(serial, subject_name.get(), validity.get(), certreq.get())); if (!certificate) { return nullptr; } PLArenaPool *arena = certificate->arena; rv = SECOID_SetAlgorithmID(arena, &certificate->signature, SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, 0); if (rv != SECSuccess) return nullptr; // Set version to X509v3. *(certificate->version.data) = SEC_CERTIFICATE_VERSION_3; certificate->version.len = 1; SECItem innerDER; innerDER.len = 0; innerDER.data = nullptr; if (!SEC_ASN1EncodeItem(arena, &innerDER, certificate.get(), SEC_ASN1_GET(CERT_CertificateTemplate))) { return nullptr; } SECItem *signedCert = PORT_ArenaZNew(arena, SECItem); if (!signedCert) { return nullptr; } rv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len, private_key.get(), SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE); if (rv != SECSuccess) { return nullptr; } certificate->derCert = *signedCert; RefPtr<DtlsIdentity> identity = new DtlsIdentity(Move(private_key), Move(certificate), ssl_kea_ecdh); return identity.forget(); }