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 */