1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/modules/libmar/verify/cryptox.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,271 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifdef XP_WIN 1.9 +#ifndef WIN32_LEAN_AND_MEAN 1.10 +#define WIN32_LEAN_AND_MEAN 1.11 +#endif 1.12 +#endif 1.13 + 1.14 +#include <stdlib.h> 1.15 +#include "cryptox.h" 1.16 + 1.17 +#if defined(MAR_NSS) 1.18 + 1.19 +/** 1.20 + * Loads the public key for the specified cert name from the NSS store. 1.21 + * 1.22 + * @param certName The cert name to find. 1.23 + * @param publicKey Out parameter for the public key to use. 1.24 + * @param cert Out parameter for the certificate to use. 1.25 + * @return CryptoX_Success on success, CryptoX_Error on error. 1.26 +*/ 1.27 +CryptoX_Result 1.28 +NSS_LoadPublicKey(const char *certNickname, 1.29 + SECKEYPublicKey **publicKey, 1.30 + CERTCertificate **cert) 1.31 +{ 1.32 + secuPWData pwdata = { PW_NONE, 0 }; 1.33 + if (!cert || !publicKey || !cert) { 1.34 + return CryptoX_Error; 1.35 + } 1.36 + 1.37 + /* Get the cert and embedded public key out of the database */ 1.38 + *cert = PK11_FindCertFromNickname(certNickname, &pwdata); 1.39 + if (!*cert) { 1.40 + return CryptoX_Error; 1.41 + } 1.42 + *publicKey = CERT_ExtractPublicKey(*cert); 1.43 + if (!*publicKey) { 1.44 + CERT_DestroyCertificate(*cert); 1.45 + return CryptoX_Error; 1.46 + } 1.47 + return CryptoX_Success; 1.48 +} 1.49 + 1.50 +CryptoX_Result 1.51 +NSS_VerifyBegin(VFYContext **ctx, 1.52 + SECKEYPublicKey * const *publicKey) 1.53 +{ 1.54 + SECStatus status; 1.55 + if (!ctx || !publicKey || !*publicKey) { 1.56 + return CryptoX_Error; 1.57 + } 1.58 + 1.59 + /* Check that the key length is large enough for our requirements */ 1.60 + if ((SECKEY_PublicKeyStrength(*publicKey) * 8) < 1.61 + XP_MIN_SIGNATURE_LEN_IN_BYTES) { 1.62 + fprintf(stderr, "ERROR: Key length must be >= %d bytes\n", 1.63 + XP_MIN_SIGNATURE_LEN_IN_BYTES); 1.64 + return CryptoX_Error; 1.65 + } 1.66 + 1.67 + *ctx = VFY_CreateContext(*publicKey, NULL, 1.68 + SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, NULL); 1.69 + if (*ctx == NULL) { 1.70 + return CryptoX_Error; 1.71 + } 1.72 + 1.73 + status = VFY_Begin(*ctx); 1.74 + return SECSuccess == status ? CryptoX_Success : CryptoX_Error; 1.75 +} 1.76 + 1.77 +/** 1.78 + * Verifies if a verify context matches the passed in signature. 1.79 + * 1.80 + * @param ctx The verify context that the signature should match. 1.81 + * @param signature The signature to match. 1.82 + * @param signatureLen The length of the signature. 1.83 + * @return CryptoX_Success on success, CryptoX_Error on error. 1.84 +*/ 1.85 +CryptoX_Result 1.86 +NSS_VerifySignature(VFYContext * const *ctx, 1.87 + const unsigned char *signature, 1.88 + unsigned int signatureLen) 1.89 +{ 1.90 + SECItem signedItem; 1.91 + SECStatus status; 1.92 + if (!ctx || !signature || !*ctx) { 1.93 + return CryptoX_Error; 1.94 + } 1.95 + 1.96 + signedItem.len = signatureLen; 1.97 + signedItem.data = (unsigned char*)signature; 1.98 + status = VFY_EndWithSignature(*ctx, &signedItem); 1.99 + return SECSuccess == status ? CryptoX_Success : CryptoX_Error; 1.100 +} 1.101 + 1.102 +#elif defined(XP_WIN) 1.103 +/** 1.104 + * Verifies if a signature + public key matches a hash context. 1.105 + * 1.106 + * @param hash The hash context that the signature should match. 1.107 + * @param pubKey The public key to use on the signature. 1.108 + * @param signature The signature to check. 1.109 + * @param signatureLen The length of the signature. 1.110 + * @return CryptoX_Success on success, CryptoX_Error on error. 1.111 +*/ 1.112 +CryptoX_Result 1.113 +CyprtoAPI_VerifySignature(HCRYPTHASH *hash, 1.114 + HCRYPTKEY *pubKey, 1.115 + const BYTE *signature, 1.116 + DWORD signatureLen) 1.117 +{ 1.118 + DWORD i; 1.119 + BOOL result; 1.120 +/* Windows APIs expect the bytes in the signature to be in little-endian 1.121 + * order, but we write the signature in big-endian order. Other APIs like 1.122 + * NSS and OpenSSL expect big-endian order. 1.123 + */ 1.124 + BYTE *signatureReversed; 1.125 + if (!hash || !pubKey || !signature || signatureLen < 1) { 1.126 + return CryptoX_Error; 1.127 + } 1.128 + 1.129 + signatureReversed = malloc(signatureLen); 1.130 + if (!signatureReversed) { 1.131 + return CryptoX_Error; 1.132 + } 1.133 + 1.134 + for (i = 0; i < signatureLen; i++) { 1.135 + signatureReversed[i] = signature[signatureLen - 1 - i]; 1.136 + } 1.137 + result = CryptVerifySignature(*hash, signatureReversed, 1.138 + signatureLen, *pubKey, NULL, 0); 1.139 + free(signatureReversed); 1.140 + return result ? CryptoX_Success : CryptoX_Error; 1.141 +} 1.142 + 1.143 +/** 1.144 + * Obtains the public key for the passed in cert data 1.145 + * 1.146 + * @param provider The cyrto provider 1.147 + * @param certData Data of the certificate to extract the public key from 1.148 + * @param sizeOfCertData The size of the certData buffer 1.149 + * @param certStore Pointer to the handle of the certificate store to use 1.150 + * @param CryptoX_Success on success 1.151 +*/ 1.152 +CryptoX_Result 1.153 +CryptoAPI_LoadPublicKey(HCRYPTPROV provider, 1.154 + BYTE *certData, 1.155 + DWORD sizeOfCertData, 1.156 + HCRYPTKEY *publicKey, 1.157 + HCERTSTORE *certStore) 1.158 +{ 1.159 + CRYPT_DATA_BLOB blob; 1.160 + CERT_CONTEXT *context; 1.161 + if (!provider || !certData || !publicKey || !certStore) { 1.162 + return CryptoX_Error; 1.163 + } 1.164 + 1.165 + blob.cbData = sizeOfCertData; 1.166 + blob.pbData = certData; 1.167 + if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, 1.168 + CERT_QUERY_CONTENT_FLAG_CERT, 1.169 + CERT_QUERY_FORMAT_FLAG_BINARY, 1.170 + 0, NULL, NULL, NULL, 1.171 + certStore, NULL, (const void **)&context)) { 1.172 + return CryptoX_Error; 1.173 + } 1.174 + 1.175 + if (!CryptImportPublicKeyInfo(provider, 1.176 + PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 1.177 + &context->pCertInfo->SubjectPublicKeyInfo, 1.178 + publicKey)) { 1.179 + CertFreeCertificateContext(context); 1.180 + return CryptoX_Error; 1.181 + } 1.182 + 1.183 + CertFreeCertificateContext(context); 1.184 + return CryptoX_Success; 1.185 +} 1.186 + 1.187 +/* Try to acquire context in this way: 1.188 + * 1. Enhanced provider without creating a new key set 1.189 + * 2. Enhanced provider with creating a new key set 1.190 + * 3. Default provider without creating a new key set 1.191 + * 4. Default provider without creating a new key set 1.192 + * #2 and #4 should not be needed because of the CRYPT_VERIFYCONTEXT, 1.193 + * but we add it just in case. 1.194 + * 1.195 + * @param provider Out parameter containing the provider handle. 1.196 + * @return CryptoX_Success on success, CryptoX_Error on error. 1.197 + */ 1.198 +CryptoX_Result 1.199 +CryptoAPI_InitCryptoContext(HCRYPTPROV *provider) 1.200 +{ 1.201 + if (!CryptAcquireContext(provider, 1.202 + NULL, 1.203 + MS_ENHANCED_PROV, 1.204 + PROV_RSA_FULL, 1.205 + CRYPT_VERIFYCONTEXT)) { 1.206 + if (!CryptAcquireContext(provider, 1.207 + NULL, 1.208 + MS_ENHANCED_PROV, 1.209 + PROV_RSA_FULL, 1.210 + CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) { 1.211 + if (!CryptAcquireContext(provider, 1.212 + NULL, 1.213 + NULL, 1.214 + PROV_RSA_FULL, 1.215 + CRYPT_VERIFYCONTEXT)) { 1.216 + if (!CryptAcquireContext(provider, 1.217 + NULL, 1.218 + NULL, 1.219 + PROV_RSA_FULL, 1.220 + CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) { 1.221 + *provider = CryptoX_InvalidHandleValue; 1.222 + return CryptoX_Error; 1.223 + } 1.224 + } 1.225 + } 1.226 + } 1.227 + return CryptoX_Success; 1.228 +} 1.229 + 1.230 +/** 1.231 + * Begins a signature verification hash context 1.232 + * 1.233 + * @param provider The crypt provider to use 1.234 + * @param hash Out parameter for a handle to the hash context 1.235 + * @return CryptoX_Success on success, CryptoX_Error on error. 1.236 +*/ 1.237 +CryptoX_Result 1.238 +CryptoAPI_VerifyBegin(HCRYPTPROV provider, HCRYPTHASH* hash) 1.239 +{ 1.240 + BOOL result; 1.241 + if (!provider || !hash) { 1.242 + return CryptoX_Error; 1.243 + } 1.244 + 1.245 + *hash = (HCRYPTHASH)NULL; 1.246 + result = CryptCreateHash(provider, CALG_SHA1, 1.247 + 0, 0, hash); 1.248 + return result ? CryptoX_Success : CryptoX_Error; 1.249 +} 1.250 + 1.251 +/** 1.252 + * Updates a signature verification hash context 1.253 + * 1.254 + * @param hash The hash context to udpate 1.255 + * @param buf The buffer to update the hash context with 1.256 + * @param len The size of the passed in buffer 1.257 + * @return CryptoX_Success on success, CryptoX_Error on error. 1.258 +*/ 1.259 +CryptoX_Result 1.260 +CryptoAPI_VerifyUpdate(HCRYPTHASH* hash, BYTE *buf, DWORD len) 1.261 +{ 1.262 + BOOL result; 1.263 + if (!hash || !buf) { 1.264 + return CryptoX_Error; 1.265 + } 1.266 + 1.267 + result = CryptHashData(*hash, buf, len, 0); 1.268 + return result ? CryptoX_Success : CryptoX_Error; 1.269 +} 1.270 + 1.271 +#endif 1.272 + 1.273 + 1.274 +