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
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;
36 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
42 SetLastError(ERROR_INVALID_PARAMETER);
46 for (i = 0; !ret && i < cAttr; i++)
47 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
52 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
53 CERT_EXTENSION rgExtensions[])
55 PCERT_EXTENSION ret = NULL;
58 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
64 SetLastError(ERROR_INVALID_PARAMETER);
68 for (i = 0; !ret && i < cExtensions; i++)
69 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
70 rgExtensions[i].pszObjId))
71 ret = &rgExtensions[i];
75 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
77 PCERT_RDN_ATTR ret = NULL;
80 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
84 SetLastError(ERROR_INVALID_PARAMETER);
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];
96 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
106 GetSystemTime(&sysTime);
107 SystemTimeToFileTime(&sysTime, &fileTime);
108 pTimeToVerify = &fileTime;
110 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
112 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
119 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
120 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
121 DWORD *pcbComputedHash)
124 HCRYPTHASH hHash = 0;
126 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
127 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
130 hCryptProv = CRYPT_GetDefaultProvider();
135 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
138 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
140 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
142 CryptDestroyHash(hHash);
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)
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);
164 SetLastError(NTE_BAD_ALGID);
169 SetLastError(ERROR_INVALID_PARAMETER);
173 ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hHash);
176 ret = CryptHashData(hHash, pbEncodedToBeSigned, cbEncodedToBeSigned, 0);
178 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
180 CryptDestroyHash(hHash);
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)
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;
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;
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;
232 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
238 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
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);
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);
259 ret = CryptImportPublicKeyInfoEx(hCryptProv,
260 dwCertEncodingType, pubKeyInfo, algID, 0, NULL, &key);
265 ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hash);
268 ret = CryptHashData(hash,
269 signedCert->ToBeSigned.pbData,
270 signedCert->ToBeSigned.cbData, 0);
273 ret = CryptVerifySignatureW(hash,
274 signedCert->Signature.pbData,
275 signedCert->Signature.cbData, key, NULL, 0);
277 CryptDestroyHash(hash);
279 CryptDestroyKey(key);
284 SetLastError(NTE_BAD_ALGID);
289 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
290 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
291 FIXME("issuer type %ld: stub\n", dwIssuerType);
294 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
297 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
302 FIXME("unimplemented for NULL signer\n");
303 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
308 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
311 LocalFree(signedCert);
317 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
318 PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
320 PCERT_ENHKEY_USAGE usage = NULL;
324 TRACE("(%p, %08lx, %p, %ld)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
326 if (!pCertContext || !pcbUsage)
328 SetLastError(ERROR_INVALID_PARAMETER);
332 if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
336 if (CertGetCertificateContextProperty(pCertContext,
337 CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
339 LPBYTE buf = CryptMemAlloc(propSize);
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);
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);
362 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
363 X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
364 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
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.)
375 SetLastError(CRYPT_E_NOT_FOUND);
379 bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
385 *pcbUsage = bytesNeeded;
386 else if (*pcbUsage < bytesNeeded)
388 SetLastError(ERROR_MORE_DATA);
389 *pcbUsage = bytesNeeded;
394 *pcbUsage = bytesNeeded;
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;
413 pUsage->cUsageIdentifier = 0;
418 TRACE("returning %d\n", ret);
422 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
423 PCERT_ENHKEY_USAGE pUsage)
427 TRACE("(%p, %p)\n", pCertContext, 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);
437 ret = CertSetCertificateContextProperty(pCertContext,
438 CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
439 LocalFree(blob.pbData);
443 ret = CertSetCertificateContextProperty(pCertContext,
444 CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
448 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
449 LPCSTR pszUsageIdentifier)
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);
463 ret = CertGetEnhancedKeyUsage(pCertContext,
464 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
467 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
468 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
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);
499 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
500 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
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);
519 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
520 LPCSTR pszUsageIdentifier)
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);
537 ret = CertGetEnhancedKeyUsage(pCertContext,
538 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
541 if (pUsage->cUsageIdentifier)
546 for (i = 0; i < pUsage->cUsageIdentifier; i++)
548 if (!strcmp(pUsage->rgpszUsageIdentifier[i],
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);
560 ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
563 CryptMemFree(pUsage);
570 /* it fit in an empty usage, therefore there's nothing to remove */
576 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
577 int *cNumOIDSs, LPSTR *rghOIDs, DWORD *pcbOIDs)
581 BOOL allUsagesValid = TRUE;
582 CERT_ENHKEY_USAGE validUsages = { 0, NULL };
584 TRACE("(%ld, %p, %p, %p, %ld)\n", cCerts, *rghCerts, cNumOIDSs,
587 for (i = 0; ret && i < cCerts; i++)
589 CERT_ENHKEY_USAGE usage;
590 DWORD size = sizeof(usage);
592 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
593 /* Success is deliberately ignored: it implies all usages are valid */
594 if (!ret && GetLastError() == ERROR_MORE_DATA)
596 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
598 allUsagesValid = FALSE;
601 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
604 if (!validUsages.cUsageIdentifier)
608 cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
609 validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
610 for (j = 0; j < validUsages.cUsageIdentifier; j++)
611 cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
613 validUsages.rgpszUsageIdentifier =
614 CryptMemAlloc(cbOIDs);
615 if (validUsages.rgpszUsageIdentifier)
617 LPSTR nextOID = (LPSTR)
618 ((LPBYTE)validUsages.rgpszUsageIdentifier +
619 validUsages.cUsageIdentifier * sizeof(LPSTR));
621 for (j = 0; j < validUsages.cUsageIdentifier; j++)
623 validUsages.rgpszUsageIdentifier[j] = nextOID;
624 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
625 pUsage->rgpszUsageIdentifier[j]);
626 nextOID += lstrlenA(nextOID) + 1;
634 DWORD j, k, validIndexes = 0, numRemoved = 0;
636 /* Merge: build a bitmap of all the indexes of
637 * validUsages.rgpszUsageIdentifier that are in pUsage.
639 for (j = 0; j < pUsage->cUsageIdentifier; j++)
641 for (k = 0; k < validUsages.cUsageIdentifier; k++)
643 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
644 validUsages.rgpszUsageIdentifier[k]))
646 validIndexes |= (1 << k);
651 /* Merge by removing from validUsages those that are
654 for (j = 0; j < validUsages.cUsageIdentifier; j++)
656 if (!(validIndexes & (1 << j)))
658 if (j < validUsages.cUsageIdentifier - 1)
660 memcpy(&validUsages.rgpszUsageIdentifier[j],
661 &validUsages.rgpszUsageIdentifier[j +
663 (validUsages.cUsageIdentifier - numRemoved
664 - j - 1) * sizeof(LPSTR));
666 validUsages.rgpszUsageIdentifier[j]) + 1 +
671 validUsages.cUsageIdentifier--;
676 CryptMemFree(pUsage);
691 if (!rghOIDs || *pcbOIDs < cbOIDs)
694 SetLastError(ERROR_MORE_DATA);
699 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
700 validUsages.cUsageIdentifier * sizeof(LPSTR));
703 *cNumOIDSs = validUsages.cUsageIdentifier;
704 for (i = 0; i < validUsages.cUsageIdentifier; i++)
706 rghOIDs[i] = nextOID;
707 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
708 nextOID += lstrlenA(nextOID) + 1;
713 CryptMemFree(validUsages.rgpszUsageIdentifier);