modules/libmar/verify/cryptox.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #ifdef XP_WIN
michael@0 6 #ifndef WIN32_LEAN_AND_MEAN
michael@0 7 #define WIN32_LEAN_AND_MEAN
michael@0 8 #endif
michael@0 9 #endif
michael@0 10
michael@0 11 #include <stdlib.h>
michael@0 12 #include "cryptox.h"
michael@0 13
michael@0 14 #if defined(MAR_NSS)
michael@0 15
michael@0 16 /**
michael@0 17 * Loads the public key for the specified cert name from the NSS store.
michael@0 18 *
michael@0 19 * @param certName The cert name to find.
michael@0 20 * @param publicKey Out parameter for the public key to use.
michael@0 21 * @param cert Out parameter for the certificate to use.
michael@0 22 * @return CryptoX_Success on success, CryptoX_Error on error.
michael@0 23 */
michael@0 24 CryptoX_Result
michael@0 25 NSS_LoadPublicKey(const char *certNickname,
michael@0 26 SECKEYPublicKey **publicKey,
michael@0 27 CERTCertificate **cert)
michael@0 28 {
michael@0 29 secuPWData pwdata = { PW_NONE, 0 };
michael@0 30 if (!cert || !publicKey || !cert) {
michael@0 31 return CryptoX_Error;
michael@0 32 }
michael@0 33
michael@0 34 /* Get the cert and embedded public key out of the database */
michael@0 35 *cert = PK11_FindCertFromNickname(certNickname, &pwdata);
michael@0 36 if (!*cert) {
michael@0 37 return CryptoX_Error;
michael@0 38 }
michael@0 39 *publicKey = CERT_ExtractPublicKey(*cert);
michael@0 40 if (!*publicKey) {
michael@0 41 CERT_DestroyCertificate(*cert);
michael@0 42 return CryptoX_Error;
michael@0 43 }
michael@0 44 return CryptoX_Success;
michael@0 45 }
michael@0 46
michael@0 47 CryptoX_Result
michael@0 48 NSS_VerifyBegin(VFYContext **ctx,
michael@0 49 SECKEYPublicKey * const *publicKey)
michael@0 50 {
michael@0 51 SECStatus status;
michael@0 52 if (!ctx || !publicKey || !*publicKey) {
michael@0 53 return CryptoX_Error;
michael@0 54 }
michael@0 55
michael@0 56 /* Check that the key length is large enough for our requirements */
michael@0 57 if ((SECKEY_PublicKeyStrength(*publicKey) * 8) <
michael@0 58 XP_MIN_SIGNATURE_LEN_IN_BYTES) {
michael@0 59 fprintf(stderr, "ERROR: Key length must be >= %d bytes\n",
michael@0 60 XP_MIN_SIGNATURE_LEN_IN_BYTES);
michael@0 61 return CryptoX_Error;
michael@0 62 }
michael@0 63
michael@0 64 *ctx = VFY_CreateContext(*publicKey, NULL,
michael@0 65 SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE, NULL);
michael@0 66 if (*ctx == NULL) {
michael@0 67 return CryptoX_Error;
michael@0 68 }
michael@0 69
michael@0 70 status = VFY_Begin(*ctx);
michael@0 71 return SECSuccess == status ? CryptoX_Success : CryptoX_Error;
michael@0 72 }
michael@0 73
michael@0 74 /**
michael@0 75 * Verifies if a verify context matches the passed in signature.
michael@0 76 *
michael@0 77 * @param ctx The verify context that the signature should match.
michael@0 78 * @param signature The signature to match.
michael@0 79 * @param signatureLen The length of the signature.
michael@0 80 * @return CryptoX_Success on success, CryptoX_Error on error.
michael@0 81 */
michael@0 82 CryptoX_Result
michael@0 83 NSS_VerifySignature(VFYContext * const *ctx,
michael@0 84 const unsigned char *signature,
michael@0 85 unsigned int signatureLen)
michael@0 86 {
michael@0 87 SECItem signedItem;
michael@0 88 SECStatus status;
michael@0 89 if (!ctx || !signature || !*ctx) {
michael@0 90 return CryptoX_Error;
michael@0 91 }
michael@0 92
michael@0 93 signedItem.len = signatureLen;
michael@0 94 signedItem.data = (unsigned char*)signature;
michael@0 95 status = VFY_EndWithSignature(*ctx, &signedItem);
michael@0 96 return SECSuccess == status ? CryptoX_Success : CryptoX_Error;
michael@0 97 }
michael@0 98
michael@0 99 #elif defined(XP_WIN)
michael@0 100 /**
michael@0 101 * Verifies if a signature + public key matches a hash context.
michael@0 102 *
michael@0 103 * @param hash The hash context that the signature should match.
michael@0 104 * @param pubKey The public key to use on the signature.
michael@0 105 * @param signature The signature to check.
michael@0 106 * @param signatureLen The length of the signature.
michael@0 107 * @return CryptoX_Success on success, CryptoX_Error on error.
michael@0 108 */
michael@0 109 CryptoX_Result
michael@0 110 CyprtoAPI_VerifySignature(HCRYPTHASH *hash,
michael@0 111 HCRYPTKEY *pubKey,
michael@0 112 const BYTE *signature,
michael@0 113 DWORD signatureLen)
michael@0 114 {
michael@0 115 DWORD i;
michael@0 116 BOOL result;
michael@0 117 /* Windows APIs expect the bytes in the signature to be in little-endian
michael@0 118 * order, but we write the signature in big-endian order. Other APIs like
michael@0 119 * NSS and OpenSSL expect big-endian order.
michael@0 120 */
michael@0 121 BYTE *signatureReversed;
michael@0 122 if (!hash || !pubKey || !signature || signatureLen < 1) {
michael@0 123 return CryptoX_Error;
michael@0 124 }
michael@0 125
michael@0 126 signatureReversed = malloc(signatureLen);
michael@0 127 if (!signatureReversed) {
michael@0 128 return CryptoX_Error;
michael@0 129 }
michael@0 130
michael@0 131 for (i = 0; i < signatureLen; i++) {
michael@0 132 signatureReversed[i] = signature[signatureLen - 1 - i];
michael@0 133 }
michael@0 134 result = CryptVerifySignature(*hash, signatureReversed,
michael@0 135 signatureLen, *pubKey, NULL, 0);
michael@0 136 free(signatureReversed);
michael@0 137 return result ? CryptoX_Success : CryptoX_Error;
michael@0 138 }
michael@0 139
michael@0 140 /**
michael@0 141 * Obtains the public key for the passed in cert data
michael@0 142 *
michael@0 143 * @param provider The cyrto provider
michael@0 144 * @param certData Data of the certificate to extract the public key from
michael@0 145 * @param sizeOfCertData The size of the certData buffer
michael@0 146 * @param certStore Pointer to the handle of the certificate store to use
michael@0 147 * @param CryptoX_Success on success
michael@0 148 */
michael@0 149 CryptoX_Result
michael@0 150 CryptoAPI_LoadPublicKey(HCRYPTPROV provider,
michael@0 151 BYTE *certData,
michael@0 152 DWORD sizeOfCertData,
michael@0 153 HCRYPTKEY *publicKey,
michael@0 154 HCERTSTORE *certStore)
michael@0 155 {
michael@0 156 CRYPT_DATA_BLOB blob;
michael@0 157 CERT_CONTEXT *context;
michael@0 158 if (!provider || !certData || !publicKey || !certStore) {
michael@0 159 return CryptoX_Error;
michael@0 160 }
michael@0 161
michael@0 162 blob.cbData = sizeOfCertData;
michael@0 163 blob.pbData = certData;
michael@0 164 if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob,
michael@0 165 CERT_QUERY_CONTENT_FLAG_CERT,
michael@0 166 CERT_QUERY_FORMAT_FLAG_BINARY,
michael@0 167 0, NULL, NULL, NULL,
michael@0 168 certStore, NULL, (const void **)&context)) {
michael@0 169 return CryptoX_Error;
michael@0 170 }
michael@0 171
michael@0 172 if (!CryptImportPublicKeyInfo(provider,
michael@0 173 PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
michael@0 174 &context->pCertInfo->SubjectPublicKeyInfo,
michael@0 175 publicKey)) {
michael@0 176 CertFreeCertificateContext(context);
michael@0 177 return CryptoX_Error;
michael@0 178 }
michael@0 179
michael@0 180 CertFreeCertificateContext(context);
michael@0 181 return CryptoX_Success;
michael@0 182 }
michael@0 183
michael@0 184 /* Try to acquire context in this way:
michael@0 185 * 1. Enhanced provider without creating a new key set
michael@0 186 * 2. Enhanced provider with creating a new key set
michael@0 187 * 3. Default provider without creating a new key set
michael@0 188 * 4. Default provider without creating a new key set
michael@0 189 * #2 and #4 should not be needed because of the CRYPT_VERIFYCONTEXT,
michael@0 190 * but we add it just in case.
michael@0 191 *
michael@0 192 * @param provider Out parameter containing the provider handle.
michael@0 193 * @return CryptoX_Success on success, CryptoX_Error on error.
michael@0 194 */
michael@0 195 CryptoX_Result
michael@0 196 CryptoAPI_InitCryptoContext(HCRYPTPROV *provider)
michael@0 197 {
michael@0 198 if (!CryptAcquireContext(provider,
michael@0 199 NULL,
michael@0 200 MS_ENHANCED_PROV,
michael@0 201 PROV_RSA_FULL,
michael@0 202 CRYPT_VERIFYCONTEXT)) {
michael@0 203 if (!CryptAcquireContext(provider,
michael@0 204 NULL,
michael@0 205 MS_ENHANCED_PROV,
michael@0 206 PROV_RSA_FULL,
michael@0 207 CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) {
michael@0 208 if (!CryptAcquireContext(provider,
michael@0 209 NULL,
michael@0 210 NULL,
michael@0 211 PROV_RSA_FULL,
michael@0 212 CRYPT_VERIFYCONTEXT)) {
michael@0 213 if (!CryptAcquireContext(provider,
michael@0 214 NULL,
michael@0 215 NULL,
michael@0 216 PROV_RSA_FULL,
michael@0 217 CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT)) {
michael@0 218 *provider = CryptoX_InvalidHandleValue;
michael@0 219 return CryptoX_Error;
michael@0 220 }
michael@0 221 }
michael@0 222 }
michael@0 223 }
michael@0 224 return CryptoX_Success;
michael@0 225 }
michael@0 226
michael@0 227 /**
michael@0 228 * Begins a signature verification hash context
michael@0 229 *
michael@0 230 * @param provider The crypt provider to use
michael@0 231 * @param hash Out parameter for a handle to the hash context
michael@0 232 * @return CryptoX_Success on success, CryptoX_Error on error.
michael@0 233 */
michael@0 234 CryptoX_Result
michael@0 235 CryptoAPI_VerifyBegin(HCRYPTPROV provider, HCRYPTHASH* hash)
michael@0 236 {
michael@0 237 BOOL result;
michael@0 238 if (!provider || !hash) {
michael@0 239 return CryptoX_Error;
michael@0 240 }
michael@0 241
michael@0 242 *hash = (HCRYPTHASH)NULL;
michael@0 243 result = CryptCreateHash(provider, CALG_SHA1,
michael@0 244 0, 0, hash);
michael@0 245 return result ? CryptoX_Success : CryptoX_Error;
michael@0 246 }
michael@0 247
michael@0 248 /**
michael@0 249 * Updates a signature verification hash context
michael@0 250 *
michael@0 251 * @param hash The hash context to udpate
michael@0 252 * @param buf The buffer to update the hash context with
michael@0 253 * @param len The size of the passed in buffer
michael@0 254 * @return CryptoX_Success on success, CryptoX_Error on error.
michael@0 255 */
michael@0 256 CryptoX_Result
michael@0 257 CryptoAPI_VerifyUpdate(HCRYPTHASH* hash, BYTE *buf, DWORD len)
michael@0 258 {
michael@0 259 BOOL result;
michael@0 260 if (!hash || !buf) {
michael@0 261 return CryptoX_Error;
michael@0 262 }
michael@0 263
michael@0 264 result = CryptHashData(*hash, buf, len, 0);
michael@0 265 return result ? CryptoX_Success : CryptoX_Error;
michael@0 266 }
michael@0 267
michael@0 268 #endif
michael@0 269
michael@0 270
michael@0 271

mercurial