michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef XP_WIN michael@0: #ifndef WIN32_LEAN_AND_MEAN michael@0: #define WIN32_LEAN_AND_MEAN michael@0: #endif michael@0: #endif michael@0: michael@0: #include michael@0: #include "cryptox.h" michael@0: michael@0: #if defined(MAR_NSS) michael@0: michael@0: /** michael@0: * Loads the public key for the specified cert name from the NSS store. michael@0: * michael@0: * @param certName The cert name to find. michael@0: * @param publicKey Out parameter for the public key to use. michael@0: * @param cert Out parameter for the certificate to use. michael@0: * @return CryptoX_Success on success, CryptoX_Error on error. michael@0: */ michael@0: CryptoX_Result michael@0: NSS_LoadPublicKey(const char *certNickname, michael@0: SECKEYPublicKey **publicKey, michael@0: CERTCertificate **cert) michael@0: { michael@0: secuPWData pwdata = { PW_NONE, 0 }; michael@0: if (!cert || !publicKey || !cert) { michael@0: return CryptoX_Error; michael@0: } michael@0: michael@0: /* Get the cert and embedded public key out of the database */ michael@0: *cert = PK11_FindCertFromNickname(certNickname, &pwdata); michael@0: if (!*cert) { michael@0: return CryptoX_Error; michael@0: } michael@0: *publicKey = CERT_ExtractPublicKey(*cert); michael@0: if (!*publicKey) { michael@0: CERT_DestroyCertificate(*cert); michael@0: return CryptoX_Error; michael@0: } michael@0: return CryptoX_Success; michael@0: } michael@0: michael@0: CryptoX_Result michael@0: NSS_VerifyBegin(VFYContext **ctx, michael@0: SECKEYPublicKey * const *publicKey) michael@0: { michael@0: SECStatus status; michael@0: if (!ctx || !publicKey || !*publicKey) { michael@0: return CryptoX_Error; michael@0: } michael@0: michael@0: /* Check that the key length is large enough for our requirements */ michael@0: if ((SECKEY_PublicKeyStrength(*publicKey) * 8) < michael@0: XP_MIN_SIGNATURE_LEN_IN_BYTES) { michael@0: fprintf(stderr, "ERROR: Key length must be >= %d bytes\n", michael@0: XP_MIN_SIGNATURE_LEN_IN_BYTES); michael@0: return CryptoX_Error; michael@0: } michael@0: michael@0: *ctx = VFY_CreateContext(*publicKey, NULL, michael@0: SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, NULL); michael@0: if (*ctx == NULL) { michael@0: return CryptoX_Error; michael@0: } michael@0: michael@0: status = VFY_Begin(*ctx); michael@0: return SECSuccess == status ? CryptoX_Success : CryptoX_Error; michael@0: } michael@0: michael@0: /** michael@0: * Verifies if a verify context matches the passed in signature. michael@0: * michael@0: * @param ctx The verify context that the signature should match. michael@0: * @param signature The signature to match. michael@0: * @param signatureLen The length of the signature. michael@0: * @return CryptoX_Success on success, CryptoX_Error on error. michael@0: */ michael@0: CryptoX_Result michael@0: NSS_VerifySignature(VFYContext * const *ctx, michael@0: const unsigned char *signature, michael@0: unsigned int signatureLen) michael@0: { michael@0: SECItem signedItem; michael@0: SECStatus status; michael@0: if (!ctx || !signature || !*ctx) { michael@0: return CryptoX_Error; michael@0: } michael@0: michael@0: signedItem.len = signatureLen; michael@0: signedItem.data = (unsigned char*)signature; michael@0: status = VFY_EndWithSignature(*ctx, &signedItem); michael@0: return SECSuccess == status ? CryptoX_Success : CryptoX_Error; michael@0: } michael@0: michael@0: #elif defined(XP_WIN) michael@0: /** michael@0: * Verifies if a signature + public key matches a hash context. michael@0: * michael@0: * @param hash The hash context that the signature should match. michael@0: * @param pubKey The public key to use on the signature. michael@0: * @param signature The signature to check. michael@0: * @param signatureLen The length of the signature. michael@0: * @return CryptoX_Success on success, CryptoX_Error on error. michael@0: */ michael@0: CryptoX_Result michael@0: CyprtoAPI_VerifySignature(HCRYPTHASH *hash, michael@0: HCRYPTKEY *pubKey, michael@0: const BYTE *signature, michael@0: DWORD signatureLen) michael@0: { michael@0: DWORD i; michael@0: BOOL result; michael@0: /* Windows APIs expect the bytes in the signature to be in little-endian michael@0: * order, but we write the signature in big-endian order. Other APIs like michael@0: * NSS and OpenSSL expect big-endian order. michael@0: */ michael@0: BYTE *signatureReversed; michael@0: if (!hash || !pubKey || !signature || signatureLen < 1) { michael@0: return CryptoX_Error; michael@0: } michael@0: michael@0: signatureReversed = malloc(signatureLen); michael@0: if (!signatureReversed) { michael@0: return CryptoX_Error; michael@0: } michael@0: michael@0: for (i = 0; i < signatureLen; i++) { michael@0: signatureReversed[i] = signature[signatureLen - 1 - i]; michael@0: } michael@0: result = CryptVerifySignature(*hash, signatureReversed, michael@0: signatureLen, *pubKey, NULL, 0); michael@0: free(signatureReversed); michael@0: return result ? CryptoX_Success : CryptoX_Error; michael@0: } michael@0: michael@0: /** michael@0: * Obtains the public key for the passed in cert data michael@0: * michael@0: * @param provider The cyrto provider michael@0: * @param certData Data of the certificate to extract the public key from michael@0: * @param sizeOfCertData The size of the certData buffer michael@0: * @param certStore Pointer to the handle of the certificate store to use michael@0: * @param CryptoX_Success on success michael@0: */ michael@0: CryptoX_Result michael@0: CryptoAPI_LoadPublicKey(HCRYPTPROV provider, michael@0: BYTE *certData, michael@0: DWORD sizeOfCertData, michael@0: HCRYPTKEY *publicKey, michael@0: HCERTSTORE *certStore) michael@0: { michael@0: CRYPT_DATA_BLOB blob; michael@0: CERT_CONTEXT *context; michael@0: if (!provider || !certData || !publicKey || !certStore) { michael@0: return CryptoX_Error; michael@0: } michael@0: michael@0: blob.cbData = sizeOfCertData; michael@0: blob.pbData = certData; michael@0: if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, michael@0: CERT_QUERY_CONTENT_FLAG_CERT, michael@0: CERT_QUERY_FORMAT_FLAG_BINARY, michael@0: 0, NULL, NULL, NULL, michael@0: certStore, NULL, (const void **)&context)) { michael@0: return CryptoX_Error; michael@0: } michael@0: michael@0: if (!CryptImportPublicKeyInfo(provider, michael@0: PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, michael@0: &context->pCertInfo->SubjectPublicKeyInfo, michael@0: publicKey)) { michael@0: CertFreeCertificateContext(context); michael@0: return CryptoX_Error; michael@0: } michael@0: michael@0: CertFreeCertificateContext(context); michael@0: return CryptoX_Success; michael@0: } michael@0: michael@0: /* Try to acquire context in this way: michael@0: * 1. Enhanced provider without creating a new key set michael@0: * 2. Enhanced provider with creating a new key set michael@0: * 3. Default provider without creating a new key set michael@0: * 4. Default provider without creating a new key set michael@0: * #2 and #4 should not be needed because of the CRYPT_VERIFYCONTEXT, michael@0: * but we add it just in case. michael@0: * michael@0: * @param provider Out parameter containing the provider handle. michael@0: * @return CryptoX_Success on success, CryptoX_Error on error. michael@0: */ michael@0: CryptoX_Result michael@0: CryptoAPI_InitCryptoContext(HCRYPTPROV *provider) michael@0: { michael@0: if (!CryptAcquireContext(provider, michael@0: NULL, michael@0: MS_ENHANCED_PROV, michael@0: PROV_RSA_FULL, michael@0: CRYPT_VERIFYCONTEXT)) { michael@0: if (!CryptAcquireContext(provider, michael@0: NULL, michael@0: MS_ENHANCED_PROV, michael@0: PROV_RSA_FULL, michael@0: CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) { michael@0: if (!CryptAcquireContext(provider, michael@0: NULL, michael@0: NULL, michael@0: PROV_RSA_FULL, michael@0: CRYPT_VERIFYCONTEXT)) { michael@0: if (!CryptAcquireContext(provider, michael@0: NULL, michael@0: NULL, michael@0: PROV_RSA_FULL, michael@0: CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) { michael@0: *provider = CryptoX_InvalidHandleValue; michael@0: return CryptoX_Error; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return CryptoX_Success; michael@0: } michael@0: michael@0: /** michael@0: * Begins a signature verification hash context michael@0: * michael@0: * @param provider The crypt provider to use michael@0: * @param hash Out parameter for a handle to the hash context michael@0: * @return CryptoX_Success on success, CryptoX_Error on error. michael@0: */ michael@0: CryptoX_Result michael@0: CryptoAPI_VerifyBegin(HCRYPTPROV provider, HCRYPTHASH* hash) michael@0: { michael@0: BOOL result; michael@0: if (!provider || !hash) { michael@0: return CryptoX_Error; michael@0: } michael@0: michael@0: *hash = (HCRYPTHASH)NULL; michael@0: result = CryptCreateHash(provider, CALG_SHA1, michael@0: 0, 0, hash); michael@0: return result ? CryptoX_Success : CryptoX_Error; michael@0: } michael@0: michael@0: /** michael@0: * Updates a signature verification hash context michael@0: * michael@0: * @param hash The hash context to udpate michael@0: * @param buf The buffer to update the hash context with michael@0: * @param len The size of the passed in buffer michael@0: * @return CryptoX_Success on success, CryptoX_Error on error. michael@0: */ michael@0: CryptoX_Result michael@0: CryptoAPI_VerifyUpdate(HCRYPTHASH* hash, BYTE *buf, DWORD len) michael@0: { michael@0: BOOL result; michael@0: if (!hash || !buf) { michael@0: return CryptoX_Error; michael@0: } michael@0: michael@0: result = CryptHashData(*hash, buf, len, 0); michael@0: return result ? CryptoX_Success : CryptoX_Error; michael@0: } michael@0: michael@0: #endif michael@0: michael@0: michael@0: