/* * CertBag via SEC_ASN1_DYNAMIC */ static const SecAsn1Template * NSS_P12_CertBagChooser( void *arg, // --> NSS_P12_CertBag Boolean enc, const char *buf, // on decode, tag byte void *dest) // --> NSS_P12_CertBag.bagValue { NSS_P12_CertBag *bag = (NSS_P12_CertBag *)arg; const SecAsn1Template *templ = NULL; NSS_P12_CertBagType type = CT_Unknown; CSSM_OID *oid = &bag->bagType; if(nssCompareCssmData(oid, &CSSMOID_PKCS9_X509Certificate)) { templ = kSecAsn1OctetStringTemplate; type = CT_X509; } else if(nssCompareCssmData(oid, &CSSMOID_PKCS9_SdsiCertificate)) { templ = kSecAsn1IA5StringTemplate; type = CT_SDSI; } else { /* punt */ templ = kSecAsn1AnyTemplate; } if(!enc) { bag->type = type; } return templ; }
static int writeAuthSafeContent( const CSSM_DATA &rawBlob, const char *outFile, SecNssCoder &coder, OidParser &parser) { NSS_P12_RawPFX pfx; memset(&pfx, 0, sizeof(pfx)); if(coder.decodeItem(rawBlob, NSS_P12_RawPFXTemplate, &pfx)) { printf("***Error on top-level decode of NSS_P12_RawPFX\n"); return 1; } printf("...version = %u\n", (unsigned)dataToInt(pfx.version)); NSS_P7_RawContentInfo &rci = pfx.authSafe; printf("...contentType = %s\n", oidStr(rci.contentType, parser)); /* parse content per OID the only special case is PKCS7_Data, * which we unwrap from an octet string before writing it */ CSSM_DATA toWrite; if(nssCompareCssmData(&rci.contentType, &CSSMOID_PKCS7_Data)) { if(coder.decodeItem(rci.content, SEC_OctetStringTemplate, &toWrite)) { printf("***Error decoding PKCS7_Data Octet string; writing" " raw contents\n"); toWrite = rci.content; } } else if(nssCompareCssmData(&rci.contentType, &CSSMOID_PKCS7_SignedData)) { /* the only other legal content type here */ /* This is encoded SignedData which I am not even close * to worrying about - Panther p12 won't do this */ toWrite = rci.content; } else { printf("***writeAuthSafeContent: bad contentType\n"); return 1; } if(writeFile(outFile, toWrite.Data, toWrite.Length)) { printf("***Error writing to %s\n", outFile); return 1; } else { printf("...%u bytes written to %s\n", (unsigned)toWrite.Length, outFile); return 0; } }
/* * NOTE: as of March 8 2004 this is also used by the SecImportExport * module...not just PKCS12! */ bool pkcsOidToParams( const CSSM_OID *oid, CSSM_ALGORITHMS &keyAlg, // e.g., CSSM_ALGID_DES CSSM_ALGORITHMS &encrAlg, // e.g., CSSM_ALGID_3DES_3KEY_EDE CSSM_ALGORITHMS &pbeHashAlg, // SHA1 or MD5 uint32 &keySizeInBits, uint32 &blockSizeInBytes, // for IV, optional CSSM_PADDING &padding, // CSSM_PADDING_PKCS7, etc. CSSM_ENCRYPT_MODE &mode, // CSSM_ALGMODE_CBCPadIV8, etc. PKCS_Which &pkcs) // PW_PKCS5_v1_5 or PW_PKCS12 { const PKCSOidInfo *info = pkcsOidInfos; pkcs = PW_None; for(unsigned dex=0; dex<NUM_PKCS_OID_INFOS; dex++) { if(nssCompareCssmData(oid, info->oid)) { keyAlg = info->keyAlg; encrAlg = info->encrAlg; pbeHashAlg = info->pbeHashAlg; keySizeInBits = info->keySizeInBits; blockSizeInBytes = info->blockSizeInBytes; padding = info->padding; mode = info->mode; pkcs = info->pkcs; return true; } info++; } return false; }
static int attrParse( const NSS_Attribute *attr, P12ParseInfo &pinfo, unsigned depth) { doIndent(depth); printf("attrType : %s\n", oidStr(attr->attrType, pinfo.mParser)); unsigned numVals = nssArraySize((const void **)attr->attrValue); doIndent(depth); printf("numValues = %u\n", numVals); for(unsigned dex=0; dex<numVals; dex++) { doIndent(depth); printf("val[%u] : ", dex); /* * Note: these two enumerated types should only have one att value * per PKCS9. Leave that to real apps, we want to see what's there * in any case. */ if(nssCompareCssmData(&attr->attrType, &CSSMOID_PKCS9_FriendlyName)) { /* BMP string (UniCode) */ CSSM_DATA ustr; if(pinfo.mCoder.decodeItem(*attr->attrValue[dex], kSecAsn1BMPStringTemplate, &ustr)) { printf("***Error decoding BMP string\n"); continue; } printDataAsUnichars(ustr); } else if(nssCompareCssmData(&attr->attrType, &CSSMOID_PKCS9_LocalKeyId)) { /* Octet string */ CSSM_DATA ostr; if(pinfo.mCoder.decodeItem(*attr->attrValue[dex], kSecAsn1ObjectIDTemplate, &ostr)) { printf("***Error decoding LocalKeyId string\n"); continue; } printDataAsHex(&ostr, 16); } else { printDataAsHex(attr->attrValue[dex], 8); } } return 0; }
static int p12Parse( const CSSM_DATA &rawBlob, P12ParseInfo &pinfo, unsigned depth) // print indent depth { NSS_P12_DecodedPFX pfx; memset(&pfx, 0, sizeof(pfx)); if(pinfo.mCoder.decodeItem(rawBlob, NSS_P12_DecodedPFXTemplate, &pfx)) { printf("***Error on top-level decode of NSS_P12_DecodedPFX\n"); return 1; } doIndent(depth); printf("version = %u\n", (unsigned)dataToInt(pfx.version)); NSS_P7_DecodedContentInfo &dci = pfx.authSafe; doIndent(depth); printf("contentType = %s\n", oidStr(dci.contentType, pinfo.mParser)); doIndent(depth); printf("type = %s\n", p7ContentInfoTypeStr(dci.type)); int rtn = 0; if(nssCompareCssmData(&dci.contentType, &CSSMOID_PKCS7_Data)) { doIndent(depth); printf("AuthenticatedSafe Length %u {\n", (unsigned)dci.content.data->Length); rtn = authSafeParse(*dci.content.data, pinfo, depth+3); doIndent(depth); printf("}\n"); } else { printf("Not parsing any other content type today.\n"); } if(pfx.macData) { doIndent(depth); printf("Mac Data {\n"); p12MacParse(*pfx.macData, pinfo, depth+3); doIndent(depth); printf("}\n"); if(pinfo.mPwd.Data == NULL) { doIndent(depth); printf("=== MAC not verified (no passphrase)===\n"); } else { CSSM_RETURN crtn = p12VerifyMac_app(pfx, pinfo.mCspHand, pinfo.mPwd, pinfo.mCoder); doIndent(depth); if(crtn) { cssmPerror("p12VerifyMac", crtn); doIndent(depth); printf("***MAC verify failure.\n"); } else { printf("MAC verifies OK.\n"); } } } return 0; }
/* * Verify MAC on an existing PFX. */ CSSM_RETURN p12VerifyMac( const NSS_P12_DecodedPFX &pfx, CSSM_CSP_HANDLE cspHand, const CSSM_DATA *pwd, // unicode, double null terminated const CSSM_KEY *passKey, SecNssCoder &coder) // for temp mallocs { if(pfx.macData == NULL) { return CSSMERR_CSP_INVALID_SIGNATURE; } NSS_P12_MacData &macData = *pfx.macData; NSS_P7_DigestInfo &digestInfo = macData.mac; CSSM_OID &algOid = digestInfo.digestAlgorithm.algorithm; CSSM_ALGORITHMS macAlg; if(!cssmOidToAlg(&algOid, &macAlg)) { return CSSMERR_CSP_INVALID_ALGORITHM; } uint32 iterCount = 0; CSSM_DATA &citer = macData.iterations; if(!p12DataToInt(citer, iterCount)) { return CSSMERR_CSP_INVALID_ATTR_ROUNDS; } if(iterCount == 0) { /* optional, default 1 */ iterCount = 1; } /* * In classic fashion, the PKCS12 spec now says: * * When password integrity mode is used to secure a PFX PDU, * an SHA-1 HMAC is computed on the BER-encoding of the contents * of the content field of the authSafe field in the PFX PDU. * * So here we go. */ CSSM_DATA genMac; CSSM_RETURN crtn = p12GenMac(cspHand, *pfx.authSafe.content.data, macAlg, iterCount, macData.macSalt, pwd, passKey, coder, genMac); if(crtn) { return crtn; } if(nssCompareCssmData(&genMac, &digestInfo.digest)) { return CSSM_OK; } else { return CSSMERR_CSP_VERIFY_FAILED; } }
/* * Given a P12KeyBag, find a matching P12CertBag. Keys and certs * "match" if their localKeyIds match. Returns NULL if not found. */ P12CertBag *P12Coder::findCertForKey( P12KeyBag *keyBag) { assert(keyBag != NULL); CSSM_DATA &keyKeyId = keyBag->localKeyIdCssm(); for(unsigned dex=0; dex<numCerts(); dex++) { P12CertBag *certBag = mCerts[dex]; CSSM_DATA &certKeyId = certBag->localKeyIdCssm(); if(nssCompareCssmData(&keyKeyId, &certKeyId)) { p12DecodeLog("findCertForKey SUCCESS"); return certBag; } } p12DecodeLog("findCertForKey FAILURE"); return NULL; }
/* * SafeBag via SEC_ASN1_DYNAMIC */ static const SecAsn1Template * NSS_P12_SafeBagChooser( void *arg, // --> NSS_P12_SafeBag Boolean enc, const char *buf, // on decode, tag byte void *dest) // --> NSS_P12_SafeBag.bagValue { NSS_P12_SafeBag *bag = (NSS_P12_SafeBag *)arg; const SecAsn1Template *templ = NULL; NSS_P12_SB_Type type = BT_None; CSSM_OID *oid = &bag->bagId; if(nssCompareCssmData(oid, &CSSMOID_PKCS12_keyBag)) { templ = NSS_P12_PtrToKeyBagTemplate; type = BT_KeyBag; } else if(nssCompareCssmData(oid, &CSSMOID_PKCS12_shroudedKeyBag)) { templ = NSS_P12_PtrToShroudedKeyBagTemplate; type = BT_ShroudedKeyBag; } else if(nssCompareCssmData(oid, &CSSMOID_PKCS12_certBag)) { templ = NSS_P12_PtrToCertBagTemplate; type = BT_CertBag; } else if(nssCompareCssmData(oid, &CSSMOID_PKCS12_crlBag)) { templ = NSS_P12_PtrToCrlBagTemplate; type = BT_CrlBag; } else if(nssCompareCssmData(oid, &CSSMOID_PKCS12_secretBag)) { templ = NSS_P12_PtrToSecretBagTemplate; type = BT_SecretBag; } else if(nssCompareCssmData(oid, &CSSMOID_PKCS12_safeContentsBag)) { templ = NSS_P12_PtrToSafeContentsBagTemplate; type = BT_SafeContentsBag; } /* add more here when we implement them */ else { templ = kSecAsn1PointerToAnyTemplate; } if(!enc) { bag->type = type; } return templ; }
/* * Given an ECDSA key in CSSM format, extract the SSL_ECDSA_NamedCurve * from its algorithm parameters. */ OSStatus sslEcdsaPeerCurve( CSSM_KEY_PTR pubKey, SSL_ECDSA_NamedCurve *namedCurve) { SecAsn1CoderRef coder = NULL; CSSM_X509_SUBJECT_PUBLIC_KEY_INFO subjPubKeyInfo; CSSM_X509_ALGORITHM_IDENTIFIER *algId = &subjPubKeyInfo.algorithm; CSSM_OID curveOid; OSStatus ortn; CSSM_KEYHEADER *hdr = &pubKey->KeyHeader; if(hdr->AlgorithmId != CSSM_ALGID_ECDSA) { sslErrorLog("sslEcdsaPeerCurve: bad peer key algorithm\n"); return errSSLProtocol; } if(hdr->BlobType != CSSM_KEYBLOB_RAW) { /* No can do - this must be raw format, it came from the CL */ sslErrorLog("sslEcdsaPeerCurve: bad peer key algorithm\n"); return errSSLProtocol; } if(hdr->Format != CSSM_KEYBLOB_RAW_FORMAT_X509) { sslErrorLog("sslEcdsaPeerCurve: bad peer key format\n"); return errSSLProtocol; } /* KeyData is an encoded CSSM_X509_SUBJECT_PUBLIC_KEY_INFO */ ortn = SecAsn1CoderCreate(&coder); if(ortn) { return errSSLInternal; } /* subsequent errors to errOut: */ memset(&subjPubKeyInfo, 0, sizeof(subjPubKeyInfo)); ortn = SecAsn1DecodeData(coder, &pubKey->KeyData, kSecAsn1SubjectPublicKeyInfoTemplate, &subjPubKeyInfo); if(ortn) { printf("sslEcdsaPeerCurve: error decoding public key\n"); goto errOut; } if(!nssCompareCssmData(&algId->algorithm, &CSSMOID_ecPublicKey)) { printf("sslEcdsaPeerCurve: unexpected algorithm ID in public key\n"); ortn = errSSLProtocol; goto errOut; } if((algId->parameters.Data[0] != BER_TAG_OID) || (algId->parameters.Length < 2)) { printf("sslEcdsaPeerCurve: missing algorithm parameters in public key\n"); ortn = errSSLProtocol; goto errOut; } /* * The curve OID is DER-encoded since the parameters are ASN_ANY. * Quickie decode for further processing... */ curveOid.Data = algId->parameters.Data + 2; curveOid.Length = algId->parameters.Length - 2; /* algId->parameters is the curve OID */ if(nssCompareCssmData(&curveOid, &CSSMOID_secp256r1)) { *namedCurve = SSL_Curve_secp256r1; } else if(nssCompareCssmData(&curveOid, &CSSMOID_secp384r1)) { *namedCurve = SSL_Curve_secp384r1; } else if(nssCompareCssmData(&curveOid, &CSSMOID_secp521r1)) { *namedCurve = SSL_Curve_secp521r1; } /* Others? Later. That's all we support for now. */ else { printf("sslEcdsaPeerCurve: missing algorithm parameters in public key\n"); ortn = errSSLProtocol; } errOut: SecAsn1CoderRelease(coder); return ortn; }