crypt32: Add stubs for CryptFindOIDInfo and I_CryptInstallAsn1Module.
[wine/dcerpc.git] / dlls / crypt32 / cert.c
blob1b38c4046adec837ab818b160a1158ca6663df0e
1 /*
2 * Copyright 2004-2006 Juan Lang
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <assert.h>
21 #include <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wincrypt.h"
25 #include "wine/debug.h"
26 #include "crypt32_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
30 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
31 CRYPT_ATTRIBUTE rgAttr[])
33 PCRYPT_ATTRIBUTE ret = NULL;
34 DWORD i;
36 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
38 if (!cAttr)
39 return NULL;
40 if (!pszObjId)
42 SetLastError(ERROR_INVALID_PARAMETER);
43 return NULL;
46 for (i = 0; !ret && i < cAttr; i++)
47 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
48 ret = &rgAttr[i];
49 return ret;
52 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
53 CERT_EXTENSION rgExtensions[])
55 PCERT_EXTENSION ret = NULL;
56 DWORD i;
58 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
60 if (!cExtensions)
61 return NULL;
62 if (!pszObjId)
64 SetLastError(ERROR_INVALID_PARAMETER);
65 return NULL;
68 for (i = 0; !ret && i < cExtensions; i++)
69 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
70 rgExtensions[i].pszObjId))
71 ret = &rgExtensions[i];
72 return ret;
75 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
77 PCERT_RDN_ATTR ret = NULL;
78 DWORD i, j;
80 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
82 if (!pszObjId)
84 SetLastError(ERROR_INVALID_PARAMETER);
85 return NULL;
88 for (i = 0; !ret && i < pName->cRDN; i++)
89 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
90 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
91 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
92 ret = &pName->rgRDN[i].rgRDNAttr[j];
93 return ret;
96 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
97 PCERT_INFO pCertInfo)
99 FILETIME fileTime;
100 LONG ret;
102 if (!pTimeToVerify)
104 SYSTEMTIME sysTime;
106 GetSystemTime(&sysTime);
107 SystemTimeToFileTime(&sysTime, &fileTime);
108 pTimeToVerify = &fileTime;
110 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
112 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
113 if (ret < 0)
114 ret = 0;
116 return ret;
119 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
120 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
121 DWORD *pcbComputedHash)
123 BOOL ret = TRUE;
124 HCRYPTHASH hHash = 0;
126 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
127 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
129 if (!hCryptProv)
130 hCryptProv = CRYPT_GetDefaultProvider();
131 if (!Algid)
132 Algid = CALG_SHA1;
133 if (ret)
135 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
136 if (ret)
138 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
139 if (ret)
140 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
141 pcbComputedHash, 0);
142 CryptDestroyHash(hHash);
145 return ret;
148 BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
149 DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
150 DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
151 const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
153 BOOL ret;
154 ALG_ID algID;
155 HCRYPTHASH hHash;
157 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv,
158 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
159 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
161 algID = CertOIDToAlgId(pSignatureAlgorithm->pszObjId);
162 if (!algID)
164 SetLastError(NTE_BAD_ALGID);
165 return FALSE;
167 if (!hCryptProv)
169 SetLastError(ERROR_INVALID_PARAMETER);
170 return FALSE;
173 ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hHash);
174 if (ret)
176 ret = CryptHashData(hHash, pbEncodedToBeSigned, cbEncodedToBeSigned, 0);
177 if (ret)
178 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
179 pcbSignature);
180 CryptDestroyHash(hHash);
182 return ret;
185 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv,
186 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
187 PCERT_PUBLIC_KEY_INFO pPublicKey)
189 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
190 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
191 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
194 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv,
195 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
196 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
198 BOOL ret = TRUE;
199 CRYPT_DATA_BLOB subjectBlob;
201 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv,
202 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
203 dwFlags, pvReserved);
205 switch (dwSubjectType)
207 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
209 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvSubject;
211 subjectBlob.pbData = blob->pbData;
212 subjectBlob.cbData = blob->cbData;
213 break;
215 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
217 PCERT_CONTEXT context = (PCERT_CONTEXT)pvSubject;
219 subjectBlob.pbData = context->pbCertEncoded;
220 subjectBlob.cbData = context->cbCertEncoded;
221 break;
223 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
225 PCRL_CONTEXT context = (PCRL_CONTEXT)pvSubject;
227 subjectBlob.pbData = context->pbCrlEncoded;
228 subjectBlob.cbData = context->cbCrlEncoded;
229 break;
231 default:
232 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
233 ret = FALSE;
236 if (ret)
238 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
239 DWORD size = 0;
241 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
242 subjectBlob.pbData, subjectBlob.cbData,
243 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
244 (BYTE *)&signedCert, &size);
245 if (ret)
247 switch (dwIssuerType)
249 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
251 PCERT_PUBLIC_KEY_INFO pubKeyInfo =
252 (PCERT_PUBLIC_KEY_INFO)pvIssuer;
253 ALG_ID algID = CertOIDToAlgId(pubKeyInfo->Algorithm.pszObjId);
255 if (algID)
257 HCRYPTKEY key;
259 ret = CryptImportPublicKeyInfoEx(hCryptProv,
260 dwCertEncodingType, pubKeyInfo, algID, 0, NULL, &key);
261 if (ret)
263 HCRYPTHASH hash;
265 ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hash);
266 if (ret)
268 ret = CryptHashData(hash,
269 signedCert->ToBeSigned.pbData,
270 signedCert->ToBeSigned.cbData, 0);
271 if (ret)
273 ret = CryptVerifySignatureW(hash,
274 signedCert->Signature.pbData,
275 signedCert->Signature.cbData, key, NULL, 0);
277 CryptDestroyHash(hash);
279 CryptDestroyKey(key);
282 else
284 SetLastError(NTE_BAD_ALGID);
285 ret = FALSE;
287 break;
289 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
290 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
291 FIXME("issuer type %ld: stub\n", dwIssuerType);
292 ret = FALSE;
293 break;
294 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
295 if (pvIssuer)
297 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
298 ret = FALSE;
300 else
302 FIXME("unimplemented for NULL signer\n");
303 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
304 ret = FALSE;
306 break;
307 default:
308 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
309 ret = FALSE;
311 LocalFree(signedCert);
314 return ret;
317 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
318 PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
320 PCERT_ENHKEY_USAGE usage = NULL;
321 DWORD bytesNeeded;
322 BOOL ret = TRUE;
324 TRACE("(%p, %08lx, %p, %ld)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
326 if (!pCertContext || !pcbUsage)
328 SetLastError(ERROR_INVALID_PARAMETER);
329 return FALSE;
332 if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
334 DWORD propSize = 0;
336 if (CertGetCertificateContextProperty(pCertContext,
337 CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
339 LPBYTE buf = CryptMemAlloc(propSize);
341 if (buf)
343 if (CertGetCertificateContextProperty(pCertContext,
344 CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
346 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
347 X509_ENHANCED_KEY_USAGE, buf, propSize,
348 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
350 CryptMemFree(buf);
354 if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
356 PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
357 pCertContext->pCertInfo->cExtension,
358 pCertContext->pCertInfo->rgExtension);
360 if (ext)
362 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
363 X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
364 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
367 if (!usage)
369 /* If a particular location is specified, this should fail. Otherwise
370 * it should succeed with an empty usage. (This is true on Win2k and
371 * later, which we emulate.)
373 if (dwFlags)
375 SetLastError(CRYPT_E_NOT_FOUND);
376 ret = FALSE;
378 else
379 bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
382 if (ret)
384 if (!pUsage)
385 *pcbUsage = bytesNeeded;
386 else if (*pcbUsage < bytesNeeded)
388 SetLastError(ERROR_MORE_DATA);
389 *pcbUsage = bytesNeeded;
390 ret = FALSE;
392 else
394 *pcbUsage = bytesNeeded;
395 if (usage)
397 DWORD i;
398 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
399 sizeof(CERT_ENHKEY_USAGE) +
400 usage->cUsageIdentifier * sizeof(LPSTR));
402 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
403 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
404 sizeof(CERT_ENHKEY_USAGE));
405 for (i = 0; i < usage->cUsageIdentifier; i++)
407 pUsage->rgpszUsageIdentifier[i] = nextOID;
408 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
409 nextOID += strlen(nextOID) + 1;
412 else
413 pUsage->cUsageIdentifier = 0;
416 if (usage)
417 LocalFree(usage);
418 TRACE("returning %d\n", ret);
419 return ret;
422 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
423 PCERT_ENHKEY_USAGE pUsage)
425 BOOL ret;
427 TRACE("(%p, %p)\n", pCertContext, pUsage);
429 if (pUsage)
431 CRYPT_DATA_BLOB blob = { 0, NULL };
433 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
434 pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
435 if (ret)
437 ret = CertSetCertificateContextProperty(pCertContext,
438 CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
439 LocalFree(blob.pbData);
442 else
443 ret = CertSetCertificateContextProperty(pCertContext,
444 CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
445 return ret;
448 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
449 LPCSTR pszUsageIdentifier)
451 BOOL ret;
452 DWORD size;
454 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
456 if (CertGetEnhancedKeyUsage(pCertContext,
457 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
459 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
461 if (usage)
463 ret = CertGetEnhancedKeyUsage(pCertContext,
464 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
465 if (ret)
467 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
468 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
470 if (newUsage)
472 LPSTR nextOID;
473 DWORD i;
475 newUsage->rgpszUsageIdentifier =
476 (LPSTR *)((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
477 nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier +
478 (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
479 for (i = 0; i < usage->cUsageIdentifier; i++)
481 newUsage->rgpszUsageIdentifier[i] = nextOID;
482 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
483 nextOID += strlen(nextOID) + 1;
485 newUsage->rgpszUsageIdentifier[i] = nextOID;
486 strcpy(nextOID, pszUsageIdentifier);
487 newUsage->cUsageIdentifier = i + 1;
488 ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
489 CryptMemFree(newUsage);
492 CryptMemFree(usage);
494 else
495 ret = FALSE;
497 else
499 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
500 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
502 if (usage)
504 usage->rgpszUsageIdentifier =
505 (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
506 usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
507 sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
508 strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
509 usage->cUsageIdentifier = 1;
510 ret = CertSetEnhancedKeyUsage(pCertContext, usage);
511 CryptMemFree(usage);
513 else
514 ret = FALSE;
516 return ret;
519 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
520 LPCSTR pszUsageIdentifier)
522 BOOL ret;
523 DWORD size;
524 CERT_ENHKEY_USAGE usage;
526 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
528 size = sizeof(usage);
529 ret = CertGetEnhancedKeyUsage(pCertContext,
530 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
531 if (!ret && GetLastError() == ERROR_MORE_DATA)
533 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
535 if (pUsage)
537 ret = CertGetEnhancedKeyUsage(pCertContext,
538 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
539 if (ret)
541 if (pUsage->cUsageIdentifier)
543 DWORD i;
544 BOOL found = FALSE;
546 for (i = 0; i < pUsage->cUsageIdentifier; i++)
548 if (!strcmp(pUsage->rgpszUsageIdentifier[i],
549 pszUsageIdentifier))
550 found = TRUE;
551 if (found && i < pUsage->cUsageIdentifier - 1)
552 pUsage->rgpszUsageIdentifier[i] =
553 pUsage->rgpszUsageIdentifier[i + 1];
555 pUsage->cUsageIdentifier--;
556 /* Remove the usage if it's empty */
557 if (pUsage->cUsageIdentifier)
558 ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
559 else
560 ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
563 CryptMemFree(pUsage);
565 else
566 ret = FALSE;
568 else
570 /* it fit in an empty usage, therefore there's nothing to remove */
571 ret = TRUE;
573 return ret;