1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef WIN32_LEAN_AND_MEAN
7 #define WIN32_LEAN_AND_MEAN
16 #pragma warning(disable: 4204)
22 * Loads the public key for the specified cert name from the NSS store.
24 * @param certData The DER-encoded X509 certificate to extract the key from.
25 * @param certDataSize The size of certData.
26 * @param publicKey Out parameter for the public key to use.
27 * @return CryptoX_Success on success, CryptoX_Error on error.
30 NSS_LoadPublicKey(const unsigned char *certData
, unsigned int certDataSize
,
31 SECKEYPublicKey
**publicKey
)
33 CERTCertificate
* cert
;
34 SECItem certDataItem
= { siBuffer
, (unsigned char*) certData
, certDataSize
};
36 if (!certData
|| !publicKey
) {
40 cert
= CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &certDataItem
, NULL
,
42 /* Get the cert and embedded public key out of the database */
46 *publicKey
= CERT_ExtractPublicKey(cert
);
47 CERT_DestroyCertificate(cert
);
52 return CryptoX_Success
;
56 NSS_VerifyBegin(VFYContext
**ctx
,
57 SECKEYPublicKey
* const *publicKey
)
60 if (!ctx
|| !publicKey
|| !*publicKey
) {
64 /* Check that the key length is large enough for our requirements */
65 if ((SECKEY_PublicKeyStrength(*publicKey
) * 8) <
66 XP_MIN_SIGNATURE_LEN_IN_BYTES
) {
67 fprintf(stderr
, "ERROR: Key length must be >= %d bytes\n",
68 XP_MIN_SIGNATURE_LEN_IN_BYTES
);
72 *ctx
= VFY_CreateContext(*publicKey
, NULL
,
73 SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE
, NULL
);
78 status
= VFY_Begin(*ctx
);
79 return SECSuccess
== status
? CryptoX_Success
: CryptoX_Error
;
83 * Verifies if a verify context matches the passed in signature.
85 * @param ctx The verify context that the signature should match.
86 * @param signature The signature to match.
87 * @param signatureLen The length of the signature.
88 * @return CryptoX_Success on success, CryptoX_Error on error.
91 NSS_VerifySignature(VFYContext
* const *ctx
,
92 const unsigned char *signature
,
93 unsigned int signatureLen
)
97 if (!ctx
|| !signature
|| !*ctx
) {
101 signedItem
.len
= signatureLen
;
102 signedItem
.data
= (unsigned char*)signature
;
103 status
= VFY_EndWithSignature(*ctx
, &signedItem
);
104 return SECSuccess
== status
? CryptoX_Success
: CryptoX_Error
;
109 * Verifies if a signature + public key matches a hash context.
111 * @param hash The hash context that the signature should match.
112 * @param pubKey The public key to use on the signature.
113 * @param signature The signature to check.
114 * @param signatureLen The length of the signature.
115 * @return CryptoX_Success on success, CryptoX_Error on error.
118 CryptoAPI_VerifySignature(HCRYPTHASH
*hash
,
120 const BYTE
*signature
,
125 /* Windows APIs expect the bytes in the signature to be in little-endian
126 * order, but we write the signature in big-endian order. Other APIs like
127 * NSS and OpenSSL expect big-endian order.
129 BYTE
*signatureReversed
;
130 if (!hash
|| !pubKey
|| !signature
|| signatureLen
< 1) {
131 return CryptoX_Error
;
134 signatureReversed
= malloc(signatureLen
);
135 if (!signatureReversed
) {
136 return CryptoX_Error
;
139 for (i
= 0; i
< signatureLen
; i
++) {
140 signatureReversed
[i
] = signature
[signatureLen
- 1 - i
];
142 result
= CryptVerifySignature(*hash
, signatureReversed
,
143 signatureLen
, *pubKey
, NULL
, 0);
144 free(signatureReversed
);
145 return result
? CryptoX_Success
: CryptoX_Error
;
149 * Obtains the public key for the passed in cert data
151 * @param provider The crypto provider
152 * @param certData Data of the certificate to extract the public key from
153 * @param sizeOfCertData The size of the certData buffer
154 * @param certStore Pointer to the handle of the certificate store to use
155 * @param CryptoX_Success on success
158 CryptoAPI_LoadPublicKey(HCRYPTPROV provider
,
160 DWORD sizeOfCertData
,
161 HCRYPTKEY
*publicKey
)
163 CRYPT_DATA_BLOB blob
;
164 CERT_CONTEXT
*context
;
165 if (!provider
|| !certData
|| !publicKey
) {
166 return CryptoX_Error
;
169 blob
.cbData
= sizeOfCertData
;
170 blob
.pbData
= certData
;
171 if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB
, &blob
,
172 CERT_QUERY_CONTENT_FLAG_CERT
,
173 CERT_QUERY_FORMAT_FLAG_BINARY
,
175 NULL
, NULL
, (const void **)&context
)) {
176 return CryptoX_Error
;
179 if (!CryptImportPublicKeyInfo(provider
,
180 PKCS_7_ASN_ENCODING
| X509_ASN_ENCODING
,
181 &context
->pCertInfo
->SubjectPublicKeyInfo
,
183 CertFreeCertificateContext(context
);
184 return CryptoX_Error
;
187 CertFreeCertificateContext(context
);
188 return CryptoX_Success
;
191 /* Try to acquire context in this way:
192 * 1. Enhanced provider without creating a new key set
193 * 2. Enhanced provider with creating a new key set
194 * 3. Default provider without creating a new key set
195 * 4. Default provider without creating a new key set
196 * #2 and #4 should not be needed because of the CRYPT_VERIFYCONTEXT,
197 * but we add it just in case.
199 * @param provider Out parameter containing the provider handle.
200 * @return CryptoX_Success on success, CryptoX_Error on error.
203 CryptoAPI_InitCryptoContext(HCRYPTPROV
*provider
)
205 if (!CryptAcquireContext(provider
,
209 CRYPT_VERIFYCONTEXT
)) {
210 if (!CryptAcquireContext(provider
,
214 CRYPT_NEWKEYSET
| CRYPT_VERIFYCONTEXT
)) {
215 if (!CryptAcquireContext(provider
,
219 CRYPT_VERIFYCONTEXT
)) {
220 if (!CryptAcquireContext(provider
,
224 CRYPT_NEWKEYSET
| CRYPT_VERIFYCONTEXT
)) {
225 *provider
= CryptoX_InvalidHandleValue
;
226 return CryptoX_Error
;
231 return CryptoX_Success
;
235 * Begins a signature verification hash context
237 * @param provider The crypt provider to use
238 * @param hash Out parameter for a handle to the hash context
239 * @return CryptoX_Success on success, CryptoX_Error on error.
242 CryptoAPI_VerifyBegin(HCRYPTPROV provider
, HCRYPTHASH
* hash
)
245 if (!provider
|| !hash
) {
246 return CryptoX_Error
;
249 *hash
= (HCRYPTHASH
)NULL
;
250 result
= CryptCreateHash(provider
, CALG_SHA1
,
252 return result
? CryptoX_Success
: CryptoX_Error
;
256 * Updates a signature verification hash context
258 * @param hash The hash context to update
259 * @param buf The buffer to update the hash context with
260 * @param len The size of the passed in buffer
261 * @return CryptoX_Success on success, CryptoX_Error on error.
264 CryptoAPI_VerifyUpdate(HCRYPTHASH
* hash
, BYTE
*buf
, DWORD len
)
268 return CryptoX_Error
;
271 result
= CryptHashData(*hash
, buf
, len
, 0);
272 return result
? CryptoX_Success
: CryptoX_Error
;