2 * crypt32 Crypt*Object functions
4 * Copyright 2007 Juan Lang
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define NONAMELESSUNION
27 #include "crypt32_private.h"
29 #include "wine/unicode.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
34 static BOOL
CRYPT_ReadBlobFromFile(LPCWSTR fileName
, PCERT_BLOB blob
)
39 TRACE("%s\n", debugstr_w(fileName
));
41 file
= CreateFileW(fileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
42 OPEN_EXISTING
, 0, NULL
);
43 if (file
!= INVALID_HANDLE_VALUE
)
46 blob
->cbData
= GetFileSize(file
, NULL
);
49 blob
->pbData
= CryptMemAlloc(blob
->cbData
);
54 ret
= ReadFile(file
, blob
->pbData
, blob
->cbData
, &read
, NULL
);
59 TRACE("returning %d\n", ret
);
63 static BOOL
CRYPT_QueryContextObject(DWORD dwObjectType
, const void *pvObject
,
64 DWORD dwExpectedContentTypeFlags
, DWORD
*pdwMsgAndCertEncodingType
,
65 DWORD
*pdwContentType
, HCERTSTORE
*phCertStore
, const void **ppvContext
)
68 const CERT_BLOB
*blob
;
75 case CERT_QUERY_OBJECT_FILE
:
76 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
77 * just read the file directly
79 ret
= CRYPT_ReadBlobFromFile((LPCWSTR
)pvObject
, &fileBlob
);
82 case CERT_QUERY_OBJECT_BLOB
:
83 blob
= (const CERT_BLOB
*)pvObject
;
87 SetLastError(E_INVALIDARG
); /* FIXME: is this the correct error? */
93 store
= CertOpenStore(CERT_STORE_PROV_MEMORY
, 0, 0,
94 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
96 if (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_CERT
)
98 ret
= pCertInterface
->addEncodedToStore(store
, X509_ASN_ENCODING
,
99 blob
->pbData
, blob
->cbData
, CERT_STORE_ADD_ALWAYS
, ppvContext
);
101 contentType
= CERT_QUERY_CONTENT_CERT
;
103 if (!ret
&& (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_CRL
))
105 ret
= pCRLInterface
->addEncodedToStore(store
, X509_ASN_ENCODING
,
106 blob
->pbData
, blob
->cbData
, CERT_STORE_ADD_ALWAYS
, ppvContext
);
108 contentType
= CERT_QUERY_CONTENT_CRL
;
110 if (!ret
&& (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_CTL
))
112 ret
= pCTLInterface
->addEncodedToStore(store
, X509_ASN_ENCODING
,
113 blob
->pbData
, blob
->cbData
, CERT_STORE_ADD_ALWAYS
, ppvContext
);
115 contentType
= CERT_QUERY_CONTENT_CTL
;
119 if (pdwMsgAndCertEncodingType
)
120 *pdwMsgAndCertEncodingType
= X509_ASN_ENCODING
;
122 *pdwContentType
= contentType
;
124 *phCertStore
= CertDuplicateStore(store
);
126 CertCloseStore(store
, 0);
127 if (blob
== &fileBlob
)
128 CryptMemFree(blob
->pbData
);
129 TRACE("returning %d\n", ret
);
133 static BOOL
CRYPT_QuerySerializedContextObject(DWORD dwObjectType
,
134 const void *pvObject
, DWORD dwExpectedContentTypeFlags
,
135 DWORD
*pdwMsgAndCertEncodingType
, DWORD
*pdwContentType
,
136 HCERTSTORE
*phCertStore
, const void **ppvContext
)
139 const CERT_BLOB
*blob
;
140 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
145 switch (dwObjectType
)
147 case CERT_QUERY_OBJECT_FILE
:
148 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
149 * just read the file directly
151 ret
= CRYPT_ReadBlobFromFile((LPCWSTR
)pvObject
, &fileBlob
);
154 case CERT_QUERY_OBJECT_BLOB
:
155 blob
= (const CERT_BLOB
*)pvObject
;
159 SetLastError(E_INVALIDARG
); /* FIXME: is this the correct error? */
165 context
= CRYPT_ReadSerializedElement(blob
->pbData
, blob
->cbData
,
166 CERT_STORE_ALL_CONTEXT_FLAG
, &contextType
);
169 DWORD contentType
, certStoreOffset
;
174 case CERT_STORE_CERTIFICATE_CONTEXT
:
175 contextInterface
= pCertInterface
;
176 contentType
= CERT_QUERY_CONTENT_SERIALIZED_CERT
;
177 certStoreOffset
= offsetof(CERT_CONTEXT
, hCertStore
);
178 if (!(dwExpectedContentTypeFlags
&
179 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT
))
181 SetLastError(ERROR_INVALID_DATA
);
186 case CERT_STORE_CRL_CONTEXT
:
187 contextInterface
= pCRLInterface
;
188 contentType
= CERT_QUERY_CONTENT_SERIALIZED_CRL
;
189 certStoreOffset
= offsetof(CRL_CONTEXT
, hCertStore
);
190 if (!(dwExpectedContentTypeFlags
&
191 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL
))
193 SetLastError(ERROR_INVALID_DATA
);
198 case CERT_STORE_CTL_CONTEXT
:
199 contextInterface
= pCTLInterface
;
200 contentType
= CERT_QUERY_CONTENT_SERIALIZED_CTL
;
201 certStoreOffset
= offsetof(CTL_CONTEXT
, hCertStore
);
202 if (!(dwExpectedContentTypeFlags
&
203 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL
))
205 SetLastError(ERROR_INVALID_DATA
);
211 SetLastError(ERROR_INVALID_DATA
);
215 if (pdwMsgAndCertEncodingType
)
216 *pdwMsgAndCertEncodingType
= X509_ASN_ENCODING
;
218 *pdwContentType
= contentType
;
220 *phCertStore
= CertDuplicateStore(
221 *(HCERTSTORE
*)((const BYTE
*)context
+ certStoreOffset
));
223 *ppvContext
= contextInterface
->duplicate(context
);
227 if (contextInterface
&& context
)
228 contextInterface
->free(context
);
229 if (blob
== &fileBlob
)
230 CryptMemFree(blob
->pbData
);
231 TRACE("returning %d\n", ret
);
235 static BOOL
CRYPT_QuerySerializedStoreObject(DWORD dwObjectType
,
236 const void *pvObject
, DWORD
*pdwMsgAndCertEncodingType
, DWORD
*pdwContentType
,
237 HCERTSTORE
*phCertStore
, HCRYPTMSG
*phMsg
)
239 LPCWSTR fileName
= (LPCWSTR
)pvObject
;
243 if (dwObjectType
!= CERT_QUERY_OBJECT_FILE
)
245 FIXME("unimplemented for non-file type %d\n", dwObjectType
);
246 SetLastError(E_INVALIDARG
); /* FIXME: is this the correct error? */
249 TRACE("%s\n", debugstr_w(fileName
));
250 file
= CreateFileW(fileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
251 OPEN_EXISTING
, 0, NULL
);
252 if (file
!= INVALID_HANDLE_VALUE
)
254 HCERTSTORE store
= CertOpenStore(CERT_STORE_PROV_MEMORY
, 0, 0,
255 CERT_STORE_CREATE_NEW_FLAG
, NULL
);
257 ret
= CRYPT_ReadSerializedStoreFromFile(file
, store
);
260 if (pdwMsgAndCertEncodingType
)
261 *pdwMsgAndCertEncodingType
= X509_ASN_ENCODING
;
263 *pdwContentType
= CERT_QUERY_CONTENT_SERIALIZED_STORE
;
265 *phCertStore
= CertDuplicateStore(store
);
267 CertCloseStore(store
, 0);
270 TRACE("returning %d\n", ret
);
274 /* Used to decode non-embedded messages */
275 static BOOL
CRYPT_QueryMessageObject(DWORD dwObjectType
, const void *pvObject
,
276 DWORD dwExpectedContentTypeFlags
, DWORD
*pdwMsgAndCertEncodingType
,
277 DWORD
*pdwContentType
, HCERTSTORE
*phCertStore
, HCRYPTMSG
*phMsg
)
280 const CERT_BLOB
*blob
;
282 HCRYPTMSG msg
= NULL
;
283 DWORD encodingType
= X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
;
285 switch (dwObjectType
)
287 case CERT_QUERY_OBJECT_FILE
:
288 /* This isn't an embedded PKCS7 message, so just read the file
291 ret
= CRYPT_ReadBlobFromFile((LPCWSTR
)pvObject
, &fileBlob
);
294 case CERT_QUERY_OBJECT_BLOB
:
295 blob
= (const CERT_BLOB
*)pvObject
;
299 SetLastError(E_INVALIDARG
); /* FIXME: is this the correct error? */
306 /* Try it first as a PKCS content info */
307 if ((dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED
) ||
308 (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED
))
310 msg
= CryptMsgOpenToDecode(encodingType
, 0, 0, 0, NULL
, NULL
);
313 ret
= CryptMsgUpdate(msg
, blob
->pbData
, blob
->cbData
, TRUE
);
316 DWORD type
, len
= sizeof(type
);
318 ret
= CryptMsgGetParam(msg
, CMSG_TYPE_PARAM
, 0, &type
, &len
);
321 if ((dwExpectedContentTypeFlags
&
322 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED
))
324 if (type
!= CMSG_SIGNED
)
326 SetLastError(ERROR_INVALID_DATA
);
329 else if (pdwContentType
)
330 *pdwContentType
= CERT_QUERY_CONTENT_PKCS7_SIGNED
;
332 else if ((dwExpectedContentTypeFlags
&
333 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED
))
335 if (type
!= CMSG_DATA
)
337 SetLastError(ERROR_INVALID_DATA
);
340 else if (pdwContentType
)
341 *pdwContentType
= CERT_QUERY_CONTENT_PKCS7_UNSIGNED
;
352 /* Failing that, try explicitly typed messages */
354 (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED
))
356 msg
= CryptMsgOpenToDecode(encodingType
, 0, CMSG_SIGNED
, 0, NULL
, NULL
);
359 ret
= CryptMsgUpdate(msg
, blob
->pbData
, blob
->cbData
, TRUE
);
366 if (msg
&& pdwContentType
)
367 *pdwContentType
= CERT_QUERY_CONTENT_PKCS7_SIGNED
;
370 (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED
))
372 msg
= CryptMsgOpenToDecode(encodingType
, 0, CMSG_DATA
, 0, NULL
, NULL
);
375 ret
= CryptMsgUpdate(msg
, blob
->pbData
, blob
->cbData
, TRUE
);
382 if (msg
&& pdwContentType
)
383 *pdwContentType
= CERT_QUERY_CONTENT_PKCS7_UNSIGNED
;
385 if (pdwMsgAndCertEncodingType
)
386 *pdwMsgAndCertEncodingType
= encodingType
;
392 *phCertStore
= CertOpenStore(CERT_STORE_PROV_MSG
, encodingType
, 0,
395 if (blob
== &fileBlob
)
396 CryptMemFree(blob
->pbData
);
397 TRACE("returning %d\n", ret
);
401 static BOOL
CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType
,
402 const void *pvObject
, DWORD dwExpectedContentTypeFlags
,
403 DWORD
*pdwMsgAndCertEncodingType
, DWORD
*pdwContentType
,
404 HCERTSTORE
*phCertStore
, HCRYPTMSG
*phMsg
)
410 TRACE("%s\n", debugstr_w((LPCWSTR
)pvObject
));
412 if (dwObjectType
!= CERT_QUERY_OBJECT_FILE
)
414 FIXME("don't know what to do for type %d embedded signed messages\n",
416 SetLastError(E_INVALIDARG
);
419 file
= CreateFileW((LPCWSTR
)pvObject
, GENERIC_READ
, FILE_SHARE_READ
,
420 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
421 if (file
!= INVALID_HANDLE_VALUE
)
423 ret
= CryptSIPRetrieveSubjectGuid((LPCWSTR
)pvObject
, file
, &subject
);
426 SIP_DISPATCH_INFO sip
;
428 memset(&sip
, 0, sizeof(sip
));
429 sip
.cbSize
= sizeof(sip
);
430 ret
= CryptSIPLoad(&subject
, 0, &sip
);
433 SIP_SUBJECTINFO subjectInfo
;
437 memset(&subjectInfo
, 0, sizeof(subjectInfo
));
438 subjectInfo
.cbSize
= sizeof(subjectInfo
);
439 subjectInfo
.pgSubjectType
= &subject
;
440 subjectInfo
.hFile
= file
;
441 subjectInfo
.pwsFileName
= (LPCWSTR
)pvObject
;
442 ret
= sip
.pfGet(&subjectInfo
, &encodingType
, 0, &blob
.cbData
,
446 blob
.pbData
= CryptMemAlloc(blob
.cbData
);
449 ret
= sip
.pfGet(&subjectInfo
, &encodingType
, 0,
450 &blob
.cbData
, blob
.pbData
);
453 ret
= CRYPT_QueryMessageObject(
454 CERT_QUERY_OBJECT_BLOB
, &blob
,
455 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED
,
456 pdwMsgAndCertEncodingType
, NULL
, phCertStore
,
458 if (ret
&& pdwContentType
)
460 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED
;
462 CryptMemFree(blob
.pbData
);
466 SetLastError(ERROR_OUTOFMEMORY
);
474 TRACE("returning %d\n", ret
);
478 BOOL WINAPI
CryptQueryObject(DWORD dwObjectType
, const void *pvObject
,
479 DWORD dwExpectedContentTypeFlags
, DWORD dwExpectedFormatTypeFlags
,
480 DWORD dwFlags
, DWORD
*pdwMsgAndCertEncodingType
, DWORD
*pdwContentType
,
481 DWORD
*pdwFormatType
, HCERTSTORE
*phCertStore
, HCRYPTMSG
*phMsg
,
482 const void **ppvContext
)
484 static const DWORD unimplementedTypes
=
485 CERT_QUERY_CONTENT_FLAG_PKCS10
| CERT_QUERY_CONTENT_FLAG_PFX
|
486 CERT_QUERY_CONTENT_FLAG_CERT_PAIR
;
489 TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
490 dwObjectType
, pvObject
, dwExpectedContentTypeFlags
,
491 dwExpectedFormatTypeFlags
, dwFlags
, pdwMsgAndCertEncodingType
,
492 pdwContentType
, pdwFormatType
, phCertStore
, phMsg
, ppvContext
);
494 if (dwExpectedContentTypeFlags
& unimplementedTypes
)
495 WARN("unimplemented for types %08x\n",
496 dwExpectedContentTypeFlags
& unimplementedTypes
);
497 if (!(dwExpectedFormatTypeFlags
& CERT_QUERY_FORMAT_FLAG_BINARY
))
499 FIXME("unimplemented for anything but binary\n");
500 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
504 *pdwFormatType
= CERT_QUERY_FORMAT_BINARY
;
514 if ((dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_CERT
) ||
515 (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_CRL
) ||
516 (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_CTL
))
518 ret
= CRYPT_QueryContextObject(dwObjectType
, pvObject
,
519 dwExpectedContentTypeFlags
, pdwMsgAndCertEncodingType
, pdwContentType
,
520 phCertStore
, ppvContext
);
523 (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE
))
525 ret
= CRYPT_QuerySerializedStoreObject(dwObjectType
, pvObject
,
526 pdwMsgAndCertEncodingType
, pdwContentType
, phCertStore
, phMsg
);
529 ((dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT
) ||
530 (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL
) ||
531 (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL
)))
533 ret
= CRYPT_QuerySerializedContextObject(dwObjectType
, pvObject
,
534 dwExpectedContentTypeFlags
, pdwMsgAndCertEncodingType
, pdwContentType
,
535 phCertStore
, ppvContext
);
538 ((dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED
) ||
539 (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED
)))
541 ret
= CRYPT_QueryMessageObject(dwObjectType
, pvObject
,
542 dwExpectedContentTypeFlags
, pdwMsgAndCertEncodingType
, pdwContentType
,
546 (dwExpectedContentTypeFlags
& CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED
))
548 ret
= CRYPT_QueryEmbeddedMessageObject(dwObjectType
, pvObject
,
549 dwExpectedContentTypeFlags
, pdwMsgAndCertEncodingType
, pdwContentType
,
552 TRACE("returning %d\n", ret
);
556 static BOOL WINAPI
CRYPT_FormatHexString(DWORD dwCertEncodingType
,
557 DWORD dwFormatType
, DWORD dwFormatStrType
, void *pFormatStruct
,
558 LPCSTR lpszStructType
, const BYTE
*pbEncoded
, DWORD cbEncoded
, void *pbFormat
,
565 bytesNeeded
= (cbEncoded
* 3) * sizeof(WCHAR
);
567 bytesNeeded
= sizeof(WCHAR
);
570 *pcbFormat
= bytesNeeded
;
573 else if (*pcbFormat
< bytesNeeded
)
575 *pcbFormat
= bytesNeeded
;
576 SetLastError(ERROR_MORE_DATA
);
581 static const WCHAR fmt
[] = { '%','0','2','x',' ',0 };
582 static const WCHAR endFmt
[] = { '%','0','2','x',0 };
584 LPWSTR ptr
= pbFormat
;
586 *pcbFormat
= bytesNeeded
;
589 for (i
= 0; i
< cbEncoded
; i
++)
591 if (i
< cbEncoded
- 1)
592 ptr
+= sprintfW(ptr
, fmt
, pbEncoded
[i
]);
594 ptr
+= sprintfW(ptr
, endFmt
, pbEncoded
[i
]);
604 #define MAX_STRING_RESOURCE_LEN 128
606 static const WCHAR crlf
[] = { '\r','\n',0 };
607 static const WCHAR commaSpace
[] = { ',',' ',0 };
609 static WCHAR subjectTypeHeader
[MAX_STRING_RESOURCE_LEN
];
610 static WCHAR subjectTypeCA
[MAX_STRING_RESOURCE_LEN
];
611 static WCHAR subjectTypeEndCert
[MAX_STRING_RESOURCE_LEN
];
612 static WCHAR pathLengthHeader
[MAX_STRING_RESOURCE_LEN
];
614 static BOOL WINAPI
CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType
,
615 DWORD dwFormatType
, DWORD dwFormatStrType
, void *pFormatStruct
,
616 LPCSTR lpszStructType
, const BYTE
*pbEncoded
, DWORD cbEncoded
, void *pbFormat
,
620 CERT_BASIC_CONSTRAINTS2_INFO
*info
;
625 SetLastError(E_INVALIDARG
);
628 if ((ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_BASIC_CONSTRAINTS2
,
629 pbEncoded
, cbEncoded
, CRYPT_DECODE_ALLOC_FLAG
, NULL
, &info
, &size
)))
631 static const WCHAR pathFmt
[] = { '%','d',0 };
632 static BOOL stringsLoaded
= FALSE
;
633 DWORD bytesNeeded
= sizeof(WCHAR
); /* space for the NULL terminator */
634 WCHAR pathLength
[MAX_STRING_RESOURCE_LEN
];
635 LPCWSTR sep
, subjectType
;
638 if (dwFormatStrType
& CRYPT_FORMAT_STR_MULTI_LINE
)
641 sepLen
= strlenW(crlf
) * sizeof(WCHAR
);
646 sepLen
= strlenW(commaSpace
) * sizeof(WCHAR
);
651 LoadStringW(hInstance
, IDS_SUBJECT_TYPE
, subjectTypeHeader
,
652 sizeof(subjectTypeHeader
) / sizeof(subjectTypeHeader
[0]));
653 LoadStringW(hInstance
, IDS_SUBJECT_TYPE_CA
, subjectTypeCA
,
654 sizeof(subjectTypeCA
) / sizeof(subjectTypeCA
[0]));
655 LoadStringW(hInstance
, IDS_SUBJECT_TYPE_END_CERT
,
657 sizeof(subjectTypeEndCert
) / sizeof(subjectTypeEndCert
[0]));
658 LoadStringW(hInstance
, IDS_PATH_LENGTH
, pathLengthHeader
,
659 sizeof(pathLengthHeader
) / sizeof(pathLengthHeader
[0]));
660 stringsLoaded
= TRUE
;
662 bytesNeeded
+= strlenW(subjectTypeHeader
) * sizeof(WCHAR
);
664 subjectType
= subjectTypeCA
;
666 subjectType
= subjectTypeEndCert
;
667 bytesNeeded
+= strlenW(subjectType
) * sizeof(WCHAR
);
668 bytesNeeded
+= sepLen
;
669 bytesNeeded
+= strlenW(pathLengthHeader
) * sizeof(WCHAR
);
670 if (info
->fPathLenConstraint
)
671 sprintfW(pathLength
, pathFmt
, info
->dwPathLenConstraint
);
673 LoadStringW(hInstance
, IDS_PATH_LENGTH_NONE
, pathLength
,
674 sizeof(pathLength
) / sizeof(pathLength
[0]));
675 bytesNeeded
+= strlenW(pathLength
) * sizeof(WCHAR
);
677 *pcbFormat
= bytesNeeded
;
678 else if (*pcbFormat
< bytesNeeded
)
680 *pcbFormat
= bytesNeeded
;
681 SetLastError(ERROR_MORE_DATA
);
686 LPWSTR str
= pbFormat
;
688 *pcbFormat
= bytesNeeded
;
689 strcpyW(str
, subjectTypeHeader
);
690 str
+= strlenW(subjectTypeHeader
);
691 strcpyW(str
, subjectType
);
692 str
+= strlenW(subjectType
);
694 str
+= sepLen
/ sizeof(WCHAR
);
695 strcpyW(str
, pathLengthHeader
);
696 str
+= strlenW(pathLengthHeader
);
697 strcpyW(str
, pathLength
);
698 str
+= strlenW(pathLength
);
705 static BOOL
CRYPT_FormatHexStringWithPrefix(CRYPT_DATA_BLOB
*blob
, int id
,
706 LPWSTR str
, DWORD
*pcbStr
)
708 WCHAR buf
[MAX_STRING_RESOURCE_LEN
];
712 LoadStringW(hInstance
, id
, buf
, sizeof(buf
) / sizeof(buf
[0]));
713 CRYPT_FormatHexString(X509_ASN_ENCODING
, 0, 0, NULL
, NULL
,
714 blob
->pbData
, blob
->cbData
, NULL
, &bytesNeeded
);
715 bytesNeeded
+= strlenW(buf
) * sizeof(WCHAR
);
718 *pcbStr
= bytesNeeded
;
721 else if (*pcbStr
< bytesNeeded
)
723 *pcbStr
= bytesNeeded
;
724 SetLastError(ERROR_MORE_DATA
);
729 *pcbStr
= bytesNeeded
;
732 bytesNeeded
-= strlenW(str
) * sizeof(WCHAR
);
733 ret
= CRYPT_FormatHexString(X509_ASN_ENCODING
, 0, 0, NULL
, NULL
,
734 blob
->pbData
, blob
->cbData
, str
, &bytesNeeded
);
739 static BOOL
CRYPT_FormatKeyId(CRYPT_DATA_BLOB
*keyId
, LPWSTR str
,
742 return CRYPT_FormatHexStringWithPrefix(keyId
, IDS_KEY_ID
, str
, pcbStr
);
745 static BOOL
CRYPT_FormatCertSerialNumber(CRYPT_DATA_BLOB
*serialNum
, LPWSTR str
,
748 return CRYPT_FormatHexStringWithPrefix(serialNum
, IDS_CERT_SERIAL_NUMBER
,
752 static BOOL
CRYPT_FormatAltNameEntry(DWORD dwFormatStrType
,
753 CERT_ALT_NAME_ENTRY
*entry
, LPWSTR str
, DWORD
*pcbStr
)
756 WCHAR buf
[MAX_STRING_RESOURCE_LEN
];
757 WCHAR mask
[MAX_STRING_RESOURCE_LEN
];
760 DWORD bytesNeeded
= sizeof(WCHAR
);
762 switch (entry
->dwAltNameChoice
)
764 case CERT_ALT_NAME_RFC822_NAME
:
765 LoadStringW(hInstance
, IDS_ALT_NAME_RFC822_NAME
, buf
,
766 sizeof(buf
) / sizeof(buf
[0]));
767 bytesNeeded
+= strlenW(entry
->u
.pwszRfc822Name
) * sizeof(WCHAR
);
770 case CERT_ALT_NAME_DNS_NAME
:
771 LoadStringW(hInstance
, IDS_ALT_NAME_DNS_NAME
, buf
,
772 sizeof(buf
) / sizeof(buf
[0]));
773 bytesNeeded
+= strlenW(entry
->u
.pwszDNSName
) * sizeof(WCHAR
);
776 case CERT_ALT_NAME_URL
:
777 LoadStringW(hInstance
, IDS_ALT_NAME_URL
, buf
,
778 sizeof(buf
) / sizeof(buf
[0]));
779 bytesNeeded
+= strlenW(entry
->u
.pwszURL
) * sizeof(WCHAR
);
782 case CERT_ALT_NAME_IP_ADDRESS
:
784 static const WCHAR ipAddrWithMaskFmt
[] = { '%','d','.','%','d','.',
785 '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
787 static const WCHAR ipAddrFmt
[] = { '%','d','.','%','d','.','%','d',
790 LoadStringW(hInstance
, IDS_ALT_NAME_IP_ADDRESS
, buf
,
791 sizeof(buf
) / sizeof(buf
[0]));
792 if (entry
->u
.IPAddress
.cbData
== 8)
794 if (dwFormatStrType
& CRYPT_FORMAT_STR_MULTI_LINE
)
796 LoadStringW(hInstance
, IDS_ALT_NAME_MASK
, mask
,
797 sizeof(mask
) / sizeof(mask
[0]));
798 bytesNeeded
+= strlenW(mask
) * sizeof(WCHAR
);
799 sprintfW(ipAddrBuf
, ipAddrFmt
,
800 entry
->u
.IPAddress
.pbData
[0],
801 entry
->u
.IPAddress
.pbData
[1],
802 entry
->u
.IPAddress
.pbData
[2],
803 entry
->u
.IPAddress
.pbData
[3]);
804 bytesNeeded
+= strlenW(ipAddrBuf
) * sizeof(WCHAR
);
805 sprintfW(maskBuf
, ipAddrFmt
,
806 entry
->u
.IPAddress
.pbData
[4],
807 entry
->u
.IPAddress
.pbData
[5],
808 entry
->u
.IPAddress
.pbData
[6],
809 entry
->u
.IPAddress
.pbData
[7]);
810 bytesNeeded
+= strlenW(maskBuf
) * sizeof(WCHAR
);
811 bytesNeeded
+= strlenW(crlf
) * sizeof(WCHAR
);
815 sprintfW(ipAddrBuf
, ipAddrWithMaskFmt
,
816 entry
->u
.IPAddress
.pbData
[0],
817 entry
->u
.IPAddress
.pbData
[1],
818 entry
->u
.IPAddress
.pbData
[2],
819 entry
->u
.IPAddress
.pbData
[3],
820 entry
->u
.IPAddress
.pbData
[4],
821 entry
->u
.IPAddress
.pbData
[5],
822 entry
->u
.IPAddress
.pbData
[6],
823 entry
->u
.IPAddress
.pbData
[7]);
824 bytesNeeded
+= (strlenW(ipAddrBuf
) + 1) * sizeof(WCHAR
);
830 FIXME("unknown IP address format (%d bytes)\n",
831 entry
->u
.IPAddress
.cbData
);
837 FIXME("unimplemented for %d\n", entry
->dwAltNameChoice
);
842 bytesNeeded
+= strlenW(buf
) * sizeof(WCHAR
);
844 *pcbStr
= bytesNeeded
;
845 else if (*pcbStr
< bytesNeeded
)
847 *pcbStr
= bytesNeeded
;
848 SetLastError(ERROR_MORE_DATA
);
853 *pcbStr
= bytesNeeded
;
856 switch (entry
->dwAltNameChoice
)
858 case CERT_ALT_NAME_RFC822_NAME
:
859 case CERT_ALT_NAME_DNS_NAME
:
860 case CERT_ALT_NAME_URL
:
861 strcpyW(str
, entry
->u
.pwszURL
);
863 case CERT_ALT_NAME_IP_ADDRESS
:
864 if (dwFormatStrType
& CRYPT_FORMAT_STR_MULTI_LINE
)
866 strcpyW(str
, ipAddrBuf
);
867 str
+= strlenW(ipAddrBuf
);
869 str
+= strlenW(crlf
);
871 str
+= strlenW(mask
);
872 strcpyW(str
, maskBuf
);
875 strcpyW(str
, ipAddrBuf
);
883 static BOOL
CRYPT_FormatAltNameInfo(DWORD dwFormatStrType
,
884 CERT_ALT_NAME_INFO
*name
, LPWSTR str
, DWORD
*pcbStr
)
886 DWORD i
, size
, bytesNeeded
= 0;
891 if (dwFormatStrType
& CRYPT_FORMAT_STR_MULTI_LINE
)
894 sepLen
= strlenW(crlf
) * sizeof(WCHAR
);
899 sepLen
= strlenW(commaSpace
) * sizeof(WCHAR
);
902 for (i
= 0; ret
&& i
< name
->cAltEntry
; i
++)
904 ret
= CRYPT_FormatAltNameEntry(dwFormatStrType
, &name
->rgAltEntry
[i
],
908 bytesNeeded
+= size
- sizeof(WCHAR
);
909 if (i
< name
->cAltEntry
- 1)
910 bytesNeeded
+= sepLen
;
915 bytesNeeded
+= sizeof(WCHAR
);
917 *pcbStr
= bytesNeeded
;
918 else if (*pcbStr
< bytesNeeded
)
920 *pcbStr
= bytesNeeded
;
921 SetLastError(ERROR_MORE_DATA
);
926 *pcbStr
= bytesNeeded
;
927 for (i
= 0; ret
&& i
< name
->cAltEntry
; i
++)
929 ret
= CRYPT_FormatAltNameEntry(dwFormatStrType
,
930 &name
->rgAltEntry
[i
], str
, &size
);
933 str
+= size
/ sizeof(WCHAR
) - 1;
934 if (i
< name
->cAltEntry
- 1)
937 str
+= sepLen
/ sizeof(WCHAR
);
946 static BOOL
CRYPT_FormatCertIssuer(DWORD dwFormatStrType
,
947 CERT_ALT_NAME_INFO
*issuer
, LPWSTR str
, DWORD
*pcbStr
)
949 WCHAR buf
[MAX_STRING_RESOURCE_LEN
];
953 LoadStringW(hInstance
, IDS_CERT_ISSUER
, buf
, sizeof(buf
) / sizeof(buf
[0]));
954 ret
= CRYPT_FormatAltNameInfo(dwFormatStrType
, issuer
, NULL
, &bytesNeeded
);
955 bytesNeeded
+= strlenW(buf
) * sizeof(WCHAR
);
959 *pcbStr
= bytesNeeded
;
960 else if (*pcbStr
< bytesNeeded
)
962 *pcbStr
= bytesNeeded
;
963 SetLastError(ERROR_MORE_DATA
);
968 *pcbStr
= bytesNeeded
;
971 bytesNeeded
-= strlenW(str
) * sizeof(WCHAR
);
972 ret
= CRYPT_FormatAltNameInfo(dwFormatStrType
, issuer
, str
,
979 static BOOL WINAPI
CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType
,
980 DWORD dwFormatType
, DWORD dwFormatStrType
, void *pFormatStruct
,
981 LPCSTR lpszStructType
, const BYTE
*pbEncoded
, DWORD cbEncoded
, void *pbFormat
,
984 CERT_AUTHORITY_KEY_ID2_INFO
*info
;
990 SetLastError(E_INVALIDARG
);
993 if ((ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_AUTHORITY_KEY_ID2
,
994 pbEncoded
, cbEncoded
, CRYPT_DECODE_ALLOC_FLAG
, NULL
, &info
, &size
)))
996 DWORD bytesNeeded
= sizeof(WCHAR
); /* space for the NULL terminator */
999 BOOL needSeparator
= FALSE
;
1001 if (dwFormatStrType
& CRYPT_FORMAT_STR_MULTI_LINE
)
1004 sepLen
= strlenW(crlf
) * sizeof(WCHAR
);
1009 sepLen
= strlenW(commaSpace
) * sizeof(WCHAR
);
1012 if (info
->KeyId
.cbData
)
1014 needSeparator
= TRUE
;
1015 ret
= CRYPT_FormatKeyId(&info
->KeyId
, NULL
, &size
);
1018 /* don't include NULL-terminator more than once */
1019 bytesNeeded
+= size
- sizeof(WCHAR
);
1022 if (info
->AuthorityCertIssuer
.cAltEntry
)
1025 bytesNeeded
+= sepLen
;
1026 needSeparator
= TRUE
;
1027 ret
= CRYPT_FormatCertIssuer(dwFormatStrType
,
1028 &info
->AuthorityCertIssuer
, NULL
, &size
);
1031 /* don't include NULL-terminator more than once */
1032 bytesNeeded
+= size
- sizeof(WCHAR
);
1035 if (info
->AuthorityCertSerialNumber
.cbData
)
1038 bytesNeeded
+= sepLen
;
1039 ret
= CRYPT_FormatCertSerialNumber(
1040 &info
->AuthorityCertSerialNumber
, NULL
, &size
);
1043 /* don't include NULL-terminator more than once */
1044 bytesNeeded
+= size
- sizeof(WCHAR
);
1050 *pcbFormat
= bytesNeeded
;
1051 else if (*pcbFormat
< bytesNeeded
)
1053 *pcbFormat
= bytesNeeded
;
1054 SetLastError(ERROR_MORE_DATA
);
1059 LPWSTR str
= pbFormat
;
1061 *pcbFormat
= bytesNeeded
;
1062 needSeparator
= FALSE
;
1063 if (info
->KeyId
.cbData
)
1065 needSeparator
= TRUE
;
1066 ret
= CRYPT_FormatKeyId(&info
->KeyId
, str
, &size
);
1068 str
+= size
/ sizeof(WCHAR
);
1070 if (info
->AuthorityCertIssuer
.cAltEntry
)
1075 str
+= sepLen
/ sizeof(WCHAR
);
1077 needSeparator
= TRUE
;
1078 ret
= CRYPT_FormatCertIssuer(dwFormatStrType
,
1079 &info
->AuthorityCertIssuer
, str
, &size
);
1081 str
+= size
/ sizeof(WCHAR
);
1083 if (info
->AuthorityCertSerialNumber
.cbData
)
1088 str
+= sepLen
/ sizeof(WCHAR
);
1090 ret
= CRYPT_FormatCertSerialNumber(
1091 &info
->AuthorityCertSerialNumber
, str
, &size
);
1100 static BOOL WINAPI
CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType
,
1101 DWORD dwFormatType
, DWORD dwFormatStrType
, void *pFormatStruct
,
1102 LPCSTR lpszStructType
, const BYTE
*pbEncoded
, DWORD cbEncoded
, void *pbFormat
,
1105 CERT_ENHKEY_USAGE
*usage
;
1111 SetLastError(E_INVALIDARG
);
1114 if ((ret
= CryptDecodeObjectEx(dwCertEncodingType
, X509_ENHANCED_KEY_USAGE
,
1115 pbEncoded
, cbEncoded
, CRYPT_DECODE_ALLOC_FLAG
, NULL
, &usage
, &size
)))
1117 WCHAR unknown
[MAX_STRING_RESOURCE_LEN
];
1119 DWORD bytesNeeded
= sizeof(WCHAR
); /* space for the NULL terminator */
1123 if (dwFormatStrType
& CRYPT_FORMAT_STR_MULTI_LINE
)
1126 sepLen
= strlenW(crlf
) * sizeof(WCHAR
);
1131 sepLen
= strlenW(commaSpace
) * sizeof(WCHAR
);
1134 LoadStringW(hInstance
, IDS_USAGE_UNKNOWN
, unknown
,
1135 sizeof(unknown
) / sizeof(unknown
[0]));
1136 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
1138 PCCRYPT_OID_INFO info
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
1139 usage
->rgpszUsageIdentifier
[i
], CRYPT_ENHKEY_USAGE_OID_GROUP_ID
);
1142 bytesNeeded
+= strlenW(info
->pwszName
) * sizeof(WCHAR
);
1144 bytesNeeded
+= strlenW(unknown
) * sizeof(WCHAR
);
1145 bytesNeeded
+= sizeof(WCHAR
); /* space */
1146 bytesNeeded
+= sizeof(WCHAR
); /* left paren */
1147 bytesNeeded
+= strlen(usage
->rgpszUsageIdentifier
[i
]) *
1149 bytesNeeded
+= sizeof(WCHAR
); /* right paren */
1150 if (i
< usage
->cUsageIdentifier
- 1)
1151 bytesNeeded
+= sepLen
;
1154 *pcbFormat
= bytesNeeded
;
1155 else if (*pcbFormat
< bytesNeeded
)
1157 *pcbFormat
= bytesNeeded
;
1158 SetLastError(ERROR_MORE_DATA
);
1163 LPWSTR str
= pbFormat
;
1165 *pcbFormat
= bytesNeeded
;
1166 for (i
= 0; i
< usage
->cUsageIdentifier
; i
++)
1168 PCCRYPT_OID_INFO info
= CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY
,
1169 usage
->rgpszUsageIdentifier
[i
],
1170 CRYPT_ENHKEY_USAGE_OID_GROUP_ID
);
1175 strcpyW(str
, info
->pwszName
);
1176 str
+= strlenW(info
->pwszName
);
1180 strcpyW(str
, unknown
);
1181 str
+= strlenW(unknown
);
1185 for (oidPtr
= usage
->rgpszUsageIdentifier
[i
]; *oidPtr
; oidPtr
++)
1189 if (i
< usage
->cUsageIdentifier
- 1)
1192 str
+= sepLen
/ sizeof(WCHAR
);
1201 typedef BOOL (WINAPI
*CryptFormatObjectFunc
)(DWORD
, DWORD
, DWORD
, void *,
1202 LPCSTR
, const BYTE
*, DWORD
, void *, DWORD
*);
1204 static CryptFormatObjectFunc
CRYPT_GetBuiltinFormatFunction(DWORD encodingType
,
1205 DWORD formatStrType
, LPCSTR lpszStructType
)
1207 CryptFormatObjectFunc format
= NULL
;
1209 if ((encodingType
& CERT_ENCODING_TYPE_MASK
) != X509_ASN_ENCODING
)
1211 SetLastError(ERROR_FILE_NOT_FOUND
);
1214 if (!HIWORD(lpszStructType
))
1216 switch (LOWORD(lpszStructType
))
1218 case LOWORD(X509_BASIC_CONSTRAINTS2
):
1219 format
= CRYPT_FormatBasicConstraints2
;
1221 case LOWORD(X509_AUTHORITY_KEY_ID2
):
1222 format
= CRYPT_FormatAuthorityKeyId2
;
1224 case LOWORD(X509_ENHANCED_KEY_USAGE
):
1225 format
= CRYPT_FormatEnhancedKeyUsage
;
1229 else if (!strcmp(lpszStructType
, szOID_BASIC_CONSTRAINTS2
))
1230 format
= CRYPT_FormatBasicConstraints2
;
1231 else if (!strcmp(lpszStructType
, szOID_AUTHORITY_KEY_IDENTIFIER2
))
1232 format
= CRYPT_FormatAuthorityKeyId2
;
1233 else if (!strcmp(lpszStructType
, szOID_ENHANCED_KEY_USAGE
))
1234 format
= CRYPT_FormatEnhancedKeyUsage
;
1235 if (!format
&& !(formatStrType
& CRYPT_FORMAT_STR_NO_HEX
))
1236 format
= CRYPT_FormatHexString
;
1240 BOOL WINAPI
CryptFormatObject(DWORD dwCertEncodingType
, DWORD dwFormatType
,
1241 DWORD dwFormatStrType
, void *pFormatStruct
, LPCSTR lpszStructType
,
1242 const BYTE
*pbEncoded
, DWORD cbEncoded
, void *pbFormat
, DWORD
*pcbFormat
)
1244 CryptFormatObjectFunc format
= NULL
;
1245 HCRYPTOIDFUNCADDR hFunc
= NULL
;
1248 TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType
,
1249 dwFormatType
, dwFormatStrType
, pFormatStruct
, debugstr_a(lpszStructType
),
1250 pbEncoded
, cbEncoded
, pbFormat
, pcbFormat
);
1252 if (!(format
= CRYPT_GetBuiltinFormatFunction(dwCertEncodingType
,
1253 dwFormatStrType
, lpszStructType
)))
1255 static HCRYPTOIDFUNCSET set
= NULL
;
1258 set
= CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC
, 0);
1259 CryptGetOIDFunctionAddress(set
, dwCertEncodingType
, lpszStructType
, 0,
1260 (void **)&format
, &hFunc
);
1263 ret
= format(dwCertEncodingType
, dwFormatType
, dwFormatStrType
,
1264 pFormatStruct
, lpszStructType
, pbEncoded
, cbEncoded
, pbFormat
,
1267 CryptFreeOIDFunctionAddress(hFunc
, 0);