/* * Given a context specified via a CSSM_CC_HANDLE, add a new * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType, * AttributeLength, and an untyped pointer. */ CSSM_RETURN impExpAddContextAttribute(CSSM_CC_HANDLE CCHandle, uint32 AttributeType, uint32 AttributeLength, const void *AttributePtr) { CSSM_CONTEXT_ATTRIBUTE newAttr; newAttr.AttributeType = AttributeType; newAttr.AttributeLength = AttributeLength; newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr; return CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr); }
/* * Given a context specified via a CSSM_CC_HANDLE, add a new * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType, * AttributeLength, and an untyped pointer. */ CSSM_RETURN p12AddContextAttribute(CSSM_CC_HANDLE CCHandle, uint32 AttributeType, uint32 AttributeLength, const void *AttributePtr) { CSSM_CONTEXT_ATTRIBUTE newAttr; CSSM_RETURN crtn; newAttr.AttributeType = AttributeType; newAttr.AttributeLength = AttributeLength; newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr; crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr); if(crtn) { p12LogCssmError("CSSM_UpdateContextAttributes", crtn); } return crtn; }
/* * Wrap a private key, yielding shrouded key bits. */ CSSM_RETURN p12WrapKey( CSSM_CSP_HANDLE cspHand, CSSM_KEY_PTR privKey, const CSSM_ACCESS_CREDENTIALS *privKeyCreds, CSSM_ALGORITHMS keyAlg, // of the unwrapping key CSSM_ALGORITHMS encrAlg, CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only uint32 keySizeInBits, uint32 blockSizeInBytes, // for IV CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. uint32 iterCount, const CSSM_DATA &salt, const CSSM_DATA *pwd, // unicode external representation const CSSM_KEY *passKey, SecNssCoder &coder, // for mallocing keyBits CSSM_DATA &shroudedKeyBits) // RETURNED { CSSM_RETURN crtn; CSSM_KEY ckey; CSSM_CC_HANDLE ccHand = 0; CSSM_KEY wrappedKey; CSSM_CONTEXT_ATTRIBUTE attr; CSSM_DATA descrData = {0, NULL}; CSSM_ACCESS_CREDENTIALS creds; /* key must be extractable */ if (!(privKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) { return errSecDataNotAvailable; } if(privKeyCreds == NULL) { /* i.e., key is from the bare CSP with no ACL support */ memset(&creds, 0, sizeof(creds)); privKeyCreds = &creds; } /* P12 style IV derivation, optional */ CSSM_DATA iv = {0, NULL}; CSSM_DATA_PTR ivPtr = NULL; if(blockSizeInBytes) { coder.allocItem(iv, blockSizeInBytes); ivPtr = &iv; } /* P12 style key derivation */ crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, keySizeInBits, iterCount, salt, pwd, passKey, iv); if(crtn) { return crtn; } /* subsequent errors to errOut: */ /* CSSM context */ crtn = CSSM_CSP_CreateSymmetricContext(cspHand, encrAlg, mode, NULL, // access cred &ckey, ivPtr, // InitVector, optional padding, NULL, // Params &ccHand); if(crtn) { p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn); goto errOut; } memset(&wrappedKey, 0, sizeof(CSSM_KEY)); /* specify PKCS8 wrap format */ attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT; attr.AttributeLength = sizeof(uint32); attr.Attribute.Uint32 = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8; crtn = CSSM_UpdateContextAttributes( ccHand, 1, &attr); if(crtn) { p12LogCssmError("CSSM_UpdateContextAttributes", crtn); goto errOut; } crtn = CSSM_WrapKey(ccHand, privKeyCreds, privKey, &descrData, // DescriptiveData &wrappedKey); if(crtn) { p12LogCssmError("CSSM_WrapKey", crtn); } else { coder.allocCopyItem(wrappedKey.KeyData, shroudedKeyBits); /* this was mallocd by CSP */ freeCssmMemory(cspHand, wrappedKey.KeyData.Data); } errOut: if(ccHand) { CSSM_DeleteContext(ccHand); } CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); return crtn; }
SECStatus ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, PRBool isTLS, KeyType keyType) { SECStatus rv = SECFailure; PRBool doDerEncode = PR_FALSE; unsigned int signatureLen; OSStatus status = noErr; CSSM_CSP_HANDLE cspHandle = 0; const CSSM_KEY *cssmKey = NULL; CSSM_ALGORITHMS sigAlg; CSSM_ALGORITHMS digestAlg; const CSSM_ACCESS_CREDENTIALS * cssmCreds = NULL; CSSM_RETURN cssmRv; CSSM_DATA hashData; CSSM_DATA signatureData; CSSM_CC_HANDLE cssmSignature = 0; const SSL3Opaque* prefix; unsigned int prefixLen; SSL3Opaque prefixAndHash[SSL_MAX_DIGEST_INFO_PREFIX + HASH_LENGTH_MAX]; buf->data = NULL; status = SecKeyGetCSPHandle(key, &cspHandle); if (status != noErr) { PORT_SetError(SEC_ERROR_INVALID_KEY); goto done; } status = SecKeyGetCSSMKey(key, &cssmKey); if (status != noErr || !cssmKey) { PORT_SetError(SEC_ERROR_NO_KEY); goto done; } /* SecKeyGetBlockSize wasn't addeded until OS X 10.6 - but the * needed information is readily available on the key itself. */ signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8; if (signatureLen == 0) { PORT_SetError(SEC_ERROR_INVALID_KEY); goto done; } buf->data = (unsigned char *)PORT_Alloc(signatureLen); if (!buf->data) goto done; /* error code was set. */ sigAlg = cssmKey->KeyHeader.AlgorithmId; digestAlg = CSSM_ALGID_NONE; switch (keyType) { case rsaKey: PORT_Assert(sigAlg == CSSM_ALGID_RSA); if (ssl3_GetDigestInfoPrefix(hash->hashAlg, &prefix, &prefixLen) != SECSuccess) { goto done; } if (prefixLen + hash->len > sizeof(prefixAndHash)) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); goto done; } memcpy(prefixAndHash, prefix, prefixLen); memcpy(prefixAndHash + prefixLen, hash->u.raw, hash->len); hashData.Data = prefixAndHash; hashData.Length = prefixLen + hash->len; break; case dsaKey: case ecKey: if (keyType == ecKey) { PORT_Assert(sigAlg == CSSM_ALGID_ECDSA); doDerEncode = PR_TRUE; } else { PORT_Assert(sigAlg == CSSM_ALGID_DSA); doDerEncode = isTLS; } if (hash->hashAlg == SEC_OID_UNKNOWN) { hashData.Data = hash->u.s.sha; hashData.Length = sizeof(hash->u.s.sha); } else { hashData.Data = hash->u.raw; hashData.Length = hash->len; } break; default: PORT_SetError(SEC_ERROR_INVALID_KEY); goto done; } PRINT_BUF(60, (NULL, "hash(es) to be signed", hashData.Data, hashData.Length)); /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least, * you can prevent the UI by setting the provider handle on the * certificate to be opened with CRYPT_SILENT, but is there an equivalent? */ status = SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault, &cssmCreds); if (status != noErr) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, status); goto done; } signatureData.Length = signatureLen; signatureData.Data = (uint8*)buf->data; cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds, cssmKey, &cssmSignature); if (cssmRv) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv); goto done; } /* See "Apple Cryptographic Service Provider Functional Specification" */ if (cssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) { /* To set RSA blinding for RSA keys */ CSSM_CONTEXT_ATTRIBUTE blindingAttr; blindingAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING; blindingAttr.AttributeLength = sizeof(uint32); blindingAttr.Attribute.Uint32 = 1; cssmRv = CSSM_UpdateContextAttributes(cssmSignature, 1, &blindingAttr); if (cssmRv) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv); goto done; } } cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, digestAlg, &signatureData); if (cssmRv) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv); goto done; } buf->len = signatureData.Length; if (doDerEncode) { SECItem derSig = {siBuffer, NULL, 0}; /* This also works for an ECDSA signature */ rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); if (rv == SECSuccess) { PORT_Free(buf->data); /* discard unencoded signature. */ *buf = derSig; /* give caller encoded signature. */ } else if (derSig.data) { PORT_Free(derSig.data); } } else { rv = SECSuccess; } PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); done: /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and * should not be freed. When the PlatformKey is freed, they will be * released. */ if (cssmSignature) CSSM_DeleteContext(cssmSignature); if (rv != SECSuccess && buf->data) { PORT_Free(buf->data); buf->data = NULL; } return rv; }
/* NULL wrap a key to specified format. */ static CSSM_RETURN nullWrapKey(CSSM_CSP_HANDLE cspHand, const CSSM_KEY *refKey, CSSM_KEYBLOB_FORMAT blobFormat, CSSM_KEY_PTR rawKey) // RETURNED { CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn; CSSM_ACCESS_CREDENTIALS creds; CSSM_DATA descData = {0, 0}; memset(rawKey, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); crtn = CSSM_CSP_CreateSymmetricContext(cspHand, CSSM_ALGID_NONE, CSSM_ALGMODE_NONE, &creds, // passPhrase NULL, // unwrappingKey NULL, // initVector CSSM_PADDING_NONE, 0, // Params &ccHand); if(crtn) { printError("cspWrapKey/CreateContext", crtn); return crtn; } if(blobFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) { /* only add this attribute if it's not the default */ CSSM_ATTRIBUTE_TYPE attrType; switch(refKey->KeyHeader.KeyClass) { case CSSM_KEYCLASS_SESSION_KEY: attrType = CSSM_ATTRIBUTE_SYMMETRIC_KEY_FORMAT; break; case CSSM_KEYCLASS_PUBLIC_KEY: attrType = CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT; break; case CSSM_KEYCLASS_PRIVATE_KEY: attrType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT; break; default: printf("***Bogus KeyClass in nullWrapKey\n"); return -1; } CSSM_CONTEXT_ATTRIBUTE attr; attr.AttributeType = attrType; attr.AttributeLength = sizeof(uint32); attr.Attribute.Uint32 = blobFormat; crtn = CSSM_UpdateContextAttributes( ccHand, 1, &attr); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } crtn = CSSM_WrapKey(ccHand, &creds, refKey, &descData, rawKey); if(crtn != CSSM_OK) { printError("CSSM_WrapKey", crtn); } if(CSSM_DeleteContext(ccHand)) { printf("CSSM_DeleteContext failure\n"); } return crtn; }
/* * CDSA private key decrypt with blinding option. */ static CSSM_RETURN _cspDecrypt(CSSM_CSP_HANDLE cspHand, uint32 algorithm, // CSSM_ALGID_FEED, etc. uint32 mode, // CSSM_ALGMODE_CBC, etc. - only for symmetric algs CSSM_PADDING padding, // CSSM_PADDING_PKCS1, etc. CSSM_BOOL blinding, const CSSM_KEY *key, // public or session key const CSSM_DATA *ctext, CSSM_DATA_PTR ptext) // RETURNED { CSSM_CC_HANDLE cryptHand; CSSM_RETURN crtn; CSSM_RETURN ocrtn = CSSM_OK; CSSM_SIZE bytesDecrypted; CSSM_DATA remData = {0, NULL}; cryptHand = genCryptHandle(cspHand, algorithm, mode, padding, key, NULL, // pubKey, NULL, // iv, 0, // effectiveKeySizeInBits, 0); // rounds if(cryptHand == 0) { return CSSMERR_CSP_INTERNAL_ERROR; } if(blinding) { CSSM_CONTEXT_ATTRIBUTE newAttr; newAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING; newAttr.AttributeLength = sizeof(uint32); newAttr.Attribute.Uint32 = 1; crtn = CSSM_UpdateContextAttributes(cryptHand, 1, &newAttr); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } crtn = CSSM_DecryptData(cryptHand, ctext, 1, ptext, 1, &bytesDecrypted, &remData); if(crtn == CSSM_OK) { // NOTE: We return the proper length in ptext.... ptext->Length = bytesDecrypted; // FIXME - sometimes get mallocd RemData here, but never any valid data // there...side effect of CSPFullPluginSession's buffer handling logic; // but will we ever actually see valid data in RemData? So far we never // have.... if(remData.Data != NULL) { appFree(remData.Data, NULL); } } else { printError("CSSM_DecryptData", crtn); ocrtn = crtn; } crtn = CSSM_DeleteContext(cryptHand); if(crtn) { printError("CSSM_DeleteContext", crtn); ocrtn = crtn; } return ocrtn; }
/* sign with RSA blinging option */ static CSSM_RETURN _cspSign(CSSM_CSP_HANDLE cspHand, uint32 algorithm, // CSSM_ALGID_FEE_MD5, etc. CSSM_KEY_PTR key, // private key const CSSM_DATA *text, CSSM_BOOL rsaBlinding, CSSM_DATA_PTR sig) // RETURNED { CSSM_CC_HANDLE sigHand; CSSM_RETURN crtn; CSSM_RETURN ocrtn = CSSM_OK; const CSSM_DATA *ptext; CSSM_DATA digest = {0, NULL}; CSSM_ALGORITHMS digestAlg = CSSM_ALGID_NONE; /* handle special cases for raw sign */ switch(algorithm) { case CSSM_ALGID_SHA1: digestAlg = CSSM_ALGID_SHA1; algorithm = CSSM_ALGID_RSA; break; case CSSM_ALGID_MD5: digestAlg = CSSM_ALGID_MD5; algorithm = CSSM_ALGID_RSA; break; case CSSM_ALGID_DSA: digestAlg = CSSM_ALGID_SHA1; algorithm = CSSM_ALGID_DSA; break; default: break; } if(digestAlg != CSSM_ALGID_NONE) { crtn = cspDigest(cspHand, digestAlg, CSSM_FALSE, // mallocDigest text, &digest); if(crtn) { return crtn; } /* sign digest with raw RSA/DSA */ ptext = &digest; } else { ptext = text; } crtn = CSSM_CSP_CreateSignatureContext(cspHand, algorithm, NULL, // passPhrase key, &sigHand); if(crtn) { printError("CSSM_CSP_CreateSignatureContext (1)", crtn); return crtn; } if(rsaBlinding) { CSSM_CONTEXT_ATTRIBUTE newAttr; newAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING; newAttr.AttributeLength = sizeof(uint32); newAttr.Attribute.Uint32 = 1; crtn = CSSM_UpdateContextAttributes(sigHand, 1, &newAttr); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } crtn = CSSM_SignData(sigHand, ptext, 1, digestAlg, sig); if(crtn) { printError("CSSM_SignData", crtn); ocrtn = crtn; } crtn = CSSM_DeleteContext(sigHand); if(crtn) { printError("CSSM_DeleteContext", crtn); ocrtn = crtn; } if(digest.Data != NULL) { CSSM_FREE(digest.Data); } return ocrtn; }
/* wrap key function. */ static CSSM_RETURN wrapKey(CSSM_CSP_HANDLE cspHand, const CSSM_KEY_PTR unwrappedKey, // must be ref const CSSM_KEY_PTR wrappingKey, CSSM_ALGORITHMS wrapAlg, CSSM_ENCRYPT_MODE wrapMode, CSSM_KEYBLOB_FORMAT wrapFormat, // NONE, PKCS7, PKCS8 CSSM_PADDING wrapPad, CSSM_KEY_PTR wrappedKey) // RETURNED { CSSM_CC_HANDLE ccHand; CSSM_RETURN crtn; CSSM_RETURN crtn2; #if WRAP_KEY_REQUIRES_CREDS CSSM_ACCESS_CREDENTIALS creds; #endif #if 0 if(unwrappedKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) { printf("Hey! you can only wrap a reference key!\n"); return CSSM_ERRCODE_INTERNAL_ERROR; } #endif memset(wrappedKey, 0, sizeof(CSSM_KEY)); memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); /* special case for NULL wrap - no wrapping key */ if((wrappingKey == NULL) || (wrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) { crtn = CSSM_CSP_CreateSymmetricContext(cspHand, wrapAlg, wrapMode, &creds, // accessCred wrappingKey, &initVector, wrapPad, // Padding NULL, // Reserved &ccHand); if(crtn) { printError("cspWrapKey/CreateContext", crtn); return CSSM_ERRCODE_INTERNAL_ERROR; } } else { crtn = CSSM_CSP_CreateAsymmetricContext(cspHand, wrapAlg, &creds, // passPhrase wrappingKey, wrapPad, // Padding &ccHand); if(crtn) { printError("cspWrapKey/CreateContext", crtn); return CSSM_ERRCODE_INTERNAL_ERROR; } /* CMS requires 8-byte IV */ crtn = AddContextAttribute(ccHand, CSSM_ATTRIBUTE_INIT_VECTOR, sizeof(CSSM_DATA), CAT_Ptr, &initVector, 0); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } if(wrapFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) { /* only add this attribute if it's not the default */ CSSM_CONTEXT_ATTRIBUTE attr; attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT; attr.AttributeLength = sizeof(uint32); attr.Attribute.Uint32 = wrapFormat; crtn = CSSM_UpdateContextAttributes( ccHand, 1, &attr); if(crtn) { printError("CSSM_UpdateContextAttributes", crtn); return crtn; } } crtn = CSSM_WrapKey(ccHand, #if WRAP_KEY_REQUIRES_CREDS &creds, #else NULL, // AccessCred #endif unwrappedKey, NULL, // DescriptiveData wrappedKey); if(crtn != CSSM_OK) { printError("CSSM_WrapKey", crtn); } if((crtn2 = CSSM_DeleteContext(ccHand))) { printError("CSSM_DeleteContext", crtn2); } return crtn; }