Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

814 lines
27 KiB

  1. //+-------------------------------------------------------------------------
  2. // Microsoft Windows
  3. //
  4. // Copyright (C) Microsoft Corporation, 1995 - 1999
  5. //
  6. // File: asn1util.cpp
  7. //
  8. // Contents: ASN.1 utility helper functions.
  9. //
  10. // Functions: Asn1UtilDecodeLength
  11. // Asn1UtilExtractContent
  12. // Asn1UtilIsPKCS7WithoutContentType
  13. // Asn1UtilAdjustEncodedLength
  14. // Asn1UtilExtractValues
  15. // Asn1UtilExtractPKCS7SignedDataContent
  16. // Asn1UtilExtractCertificateToBeSignedContent
  17. // Asn1UtilExtractCertificatePublicKeyInfo
  18. // Asn1UtilExtractKeyIdFromCertInfo
  19. //
  20. // History: 04-Dec-96 philh created from kevinr's wincrmsg version
  21. //--------------------------------------------------------------------------
  22. #include "global.hxx"
  23. #include <dbgdef.h>
  24. //+-------------------------------------------------------------------------
  25. // Get the number of contents octets in a BER encoding.
  26. //
  27. // Parameters:
  28. // pcbContent - receives the number of contents octets if definite
  29. // encoding, else CMSG_INDEFINITE_LENGTH
  30. // pbLength - points to the first length octet
  31. // cbDER - number of bytes remaining in the encoding
  32. //
  33. // Returns:
  34. // success - the number of bytes in the length field, >0
  35. // failure - <0
  36. //--------------------------------------------------------------------------
  37. LONG
  38. WINAPI
  39. Asn1UtilDecodeLength(
  40. OUT DWORD *pcbContent,
  41. IN const BYTE *pbLength,
  42. IN DWORD cbEncoded)
  43. {
  44. long i;
  45. BYTE cbLength;
  46. const BYTE *pb;
  47. if (cbEncoded < 1)
  48. goto TooLittleData;
  49. if (0x80 == *pbLength) {
  50. *pcbContent = CMSG_INDEFINITE_LENGTH;
  51. i = 1;
  52. goto CommonReturn;
  53. }
  54. // determine the number of length octets and contents octets
  55. if ((cbLength = *pbLength) & 0x80) {
  56. cbLength &= ~0x80; // low 7 bits have number of bytes
  57. if (cbLength > 4)
  58. goto LengthTooLargeError;
  59. if (cbLength >= cbEncoded)
  60. goto TooLittleData;
  61. *pcbContent = 0;
  62. for (i=cbLength, pb=pbLength+1; i>0; i--, pb++)
  63. *pcbContent = (*pcbContent << 8) + (const DWORD)*pb;
  64. i = cbLength + 1;
  65. } else {
  66. *pcbContent = (DWORD)cbLength;
  67. i = 1;
  68. }
  69. CommonReturn:
  70. return i; // how many bytes there were in the length field
  71. ErrorReturn:
  72. i = -1;
  73. goto CommonReturn;
  74. TooLittleData:
  75. i = ASN1UTIL_INSUFFICIENT_DATA;
  76. goto CommonReturn;
  77. TRACE_ERROR(LengthTooLargeError)
  78. }
  79. //+-------------------------------------------------------------------------
  80. // Point to the content octets in a BER-encoded blob.
  81. //
  82. // Returns:
  83. // success - the number of bytes skipped, >=0
  84. // failure - <0
  85. //
  86. // NB- If the blob is indefinite-length encoded, *pcbContent is set to
  87. // CMSG_INDEFINITE_LENGTH
  88. //--------------------------------------------------------------------------
  89. LONG
  90. WINAPI
  91. Asn1UtilExtractContent(
  92. IN const BYTE *pbEncoded,
  93. IN DWORD cbEncoded,
  94. OUT DWORD *pcbContent,
  95. OUT const BYTE **ppbContent)
  96. {
  97. #define TAG_MASK 0x1f
  98. DWORD cbIdentifier;
  99. DWORD cbContent;
  100. LONG cbLength;
  101. LONG lHeader;
  102. const BYTE *pb = pbEncoded;
  103. if (0 == cbEncoded--)
  104. goto TooLittleData;
  105. // Skip over the identifier octet(s)
  106. if (TAG_MASK == (*pb++ & TAG_MASK)) {
  107. // high-tag-number form
  108. cbIdentifier = 2;
  109. while (TRUE) {
  110. if (0 == cbEncoded--)
  111. goto TooLittleData;
  112. if (0 == (*pb++ & 0x80))
  113. break;
  114. cbIdentifier++;
  115. }
  116. } else {
  117. // low-tag-number form
  118. cbIdentifier = 1;
  119. }
  120. if (0 > (cbLength = Asn1UtilDecodeLength( &cbContent, pb, cbEncoded))) {
  121. lHeader = cbLength;
  122. goto CommonReturn;
  123. }
  124. pb += cbLength;
  125. *pcbContent = cbContent;
  126. *ppbContent = pb;
  127. lHeader = cbLength + cbIdentifier;
  128. CommonReturn:
  129. return lHeader;
  130. TooLittleData:
  131. lHeader = ASN1UTIL_INSUFFICIENT_DATA;
  132. goto CommonReturn;
  133. }
  134. //+-------------------------------------------------------------------------
  135. // Returns TRUE if we believe this is a Bob special that has ommitted the
  136. // PKCS #7 ContentType.
  137. //
  138. // For PKCS #7: an Object Identifier tag (0x06) immediately follows the
  139. // identifier and length octets. For a Bob special: an integer tag (0x02)
  140. // follows the identifier and length octets.
  141. //--------------------------------------------------------------------------
  142. BOOL
  143. WINAPI
  144. Asn1UtilIsPKCS7WithoutContentType(
  145. IN const BYTE *pbDER,
  146. IN DWORD cbDER)
  147. {
  148. DWORD cbContent;
  149. const BYTE *pbContent;
  150. // Handle MappedFile Exceptions
  151. __try {
  152. if (0 < Asn1UtilExtractContent(pbDER, cbDER, &cbContent, &pbContent) &&
  153. (pbContent < pbDER + cbDER) &&
  154. (0x02 == *pbContent))
  155. return TRUE;
  156. else
  157. return FALSE;
  158. } __except(EXCEPTION_EXECUTE_HANDLER) {
  159. SetLastError(GetExceptionCode());
  160. return FALSE;
  161. }
  162. }
  163. //+-------------------------------------------------------------------------
  164. // Decode the Asn1 length bytes to possibly downward adjust the length.
  165. //
  166. // The returned length is always <= cbDER.
  167. //--------------------------------------------------------------------------
  168. DWORD
  169. WINAPI
  170. Asn1UtilAdjustEncodedLength(
  171. IN const BYTE *pbDER,
  172. IN DWORD cbDER
  173. )
  174. {
  175. // Decode the header to get the real length. I've seen files with extra
  176. // stuff.
  177. LONG lLen;
  178. DWORD cbLen;
  179. DWORD cbContent;
  180. const BYTE *pbContent;
  181. lLen = Asn1UtilExtractContent(pbDER, cbDER, &cbContent, &pbContent);
  182. if ((lLen >= 0) && (cbContent != CMSG_INDEFINITE_LENGTH)) {
  183. cbLen = (DWORD)lLen + cbContent;
  184. if (cbLen < cbDER)
  185. cbDER = cbLen;
  186. // else if (cbLen > cbDER)
  187. // DER length exceeds input file
  188. }
  189. // else
  190. // Can't decode DER length
  191. return cbDER;
  192. }
  193. //+-------------------------------------------------------------------------
  194. // Extract one or more tagged values from the ASN.1 encoded byte array.
  195. //
  196. // Either steps into the value's content octets (ASN1UTIL_STEP_INTO_VALUE_OP)
  197. // or steps over the value's tag, length and content octets
  198. // (ASN1UTIL_STEP_OVER_VALUE_OP or ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP).
  199. //
  200. // For tag matching, only supports single byte tags. STEP_OVER values
  201. // must be definite-length encoded.
  202. //
  203. // *pcValue is updated with the number of values successfully extracted.
  204. //
  205. // Returns:
  206. // success - >= 0 => length of all values successfully extracted. For
  207. // STEP_INTO, only the tag and length octets.
  208. // failure - < 0 => negative (offset + 1) of first bad tagged value
  209. // LastError is updated with the error.
  210. //
  211. // A non-NULL rgValueBlob[] is updated with the pointer to and length of the
  212. // tagged value or its content octets. For OPTIONAL_STEP_OVER, if tag isn't
  213. // found, pbData and cbData are set to 0. If a STEP_INTO value is
  214. // indefinite-length encoded, cbData is set to CMSG_INDEFINITE_LENGTH.
  215. // If ASN1UTIL_DEFINITE_LENGTH_FLAG is set, then, all returned lengths
  216. // are definite-length, ie, CMSG_INDEFINITE_LENGTH is never returned.
  217. //
  218. // If ASN1UTIL_RETURN_VALUE_BLOB_FLAG is set, pbData points to
  219. // the tag. cbData includes the tag, length and content octets.
  220. //
  221. // If ASN1UTIL_RETURN_CONTENT_BLOB_FLAG is set, pbData points to the content
  222. // octets. cbData includes only the content octets.
  223. //
  224. // If neither BLOB_FLAG is set, rgValueBlob[] isn't updated.
  225. //--------------------------------------------------------------------------
  226. LONG
  227. WINAPI
  228. Asn1UtilExtractValues(
  229. IN const BYTE *pbEncoded,
  230. IN DWORD cbEncoded,
  231. IN DWORD dwFlags,
  232. IN OUT DWORD *pcValue,
  233. IN const ASN1UTIL_EXTRACT_VALUE_PARA *rgValuePara,
  234. OUT OPTIONAL PCRYPT_DER_BLOB rgValueBlob
  235. )
  236. {
  237. DWORD cValue = *pcValue;
  238. const BYTE *pb = pbEncoded;
  239. DWORD cb = cbEncoded;
  240. DWORD iValue;
  241. LONG lAllValues;
  242. for (iValue = 0; iValue < cValue; iValue++) {
  243. DWORD dwParaFlags = rgValuePara[iValue].dwFlags;
  244. DWORD dwOp = dwParaFlags & ASN1UTIL_MASK_VALUE_OP;
  245. const BYTE *pbParaTag = rgValuePara[iValue].rgbTag;
  246. BOOL fValueBlob = (dwParaFlags & (ASN1UTIL_RETURN_VALUE_BLOB_FLAG |
  247. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG)) && rgValueBlob;
  248. LONG lTagLength;
  249. DWORD cbContent;
  250. const BYTE *pbContent;
  251. DWORD cbValue;
  252. if (0 == cb) {
  253. if (ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP != dwOp)
  254. goto TooLittleData;
  255. if (fValueBlob) {
  256. rgValueBlob[iValue].pbData = NULL;
  257. rgValueBlob[iValue].cbData = 0;
  258. }
  259. continue;
  260. }
  261. // Assumption: single byte tag for doing comparison
  262. if (pbParaTag) {
  263. // Check if the encoded tag matches one of the expected tags
  264. BYTE bEncodedTag;
  265. BYTE bParaTag;
  266. bEncodedTag = *pb;
  267. while ((bParaTag = *pbParaTag) && bParaTag != bEncodedTag)
  268. pbParaTag++;
  269. if (0 == bParaTag) {
  270. if (ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP != dwOp)
  271. goto InvalidTag;
  272. if (fValueBlob) {
  273. rgValueBlob[iValue].pbData = NULL;
  274. rgValueBlob[iValue].cbData = 0;
  275. }
  276. continue;
  277. }
  278. }
  279. lTagLength = Asn1UtilExtractContent(
  280. pb,
  281. cb,
  282. &cbContent,
  283. &pbContent
  284. );
  285. if (0 >= lTagLength || (DWORD) lTagLength > cb)
  286. goto InvalidTagOrLength;
  287. if (CMSG_INDEFINITE_LENGTH == cbContent) {
  288. if (ASN1UTIL_STEP_INTO_VALUE_OP != dwOp)
  289. goto UnsupportedIndefiniteLength;
  290. else if (fValueBlob && (dwFlags & ASN1UTIL_DEFINITE_LENGTH_FLAG))
  291. goto NotAllowedIndefiniteLength;
  292. cbValue = CMSG_INDEFINITE_LENGTH;
  293. } else {
  294. cbValue = cbContent + lTagLength;
  295. if (cbValue > cb)
  296. goto TooLittleData;
  297. }
  298. if (fValueBlob) {
  299. if (dwParaFlags & ASN1UTIL_RETURN_CONTENT_BLOB_FLAG) {
  300. rgValueBlob[iValue].pbData = (BYTE *) pbContent;
  301. rgValueBlob[iValue].cbData = cbContent;
  302. } else if (dwParaFlags & ASN1UTIL_RETURN_VALUE_BLOB_FLAG) {
  303. rgValueBlob[iValue].pbData = (BYTE *) pb;
  304. rgValueBlob[iValue].cbData = cbValue;
  305. }
  306. }
  307. switch (dwOp) {
  308. case ASN1UTIL_STEP_INTO_VALUE_OP:
  309. pb += lTagLength;
  310. cb -= lTagLength;
  311. break;
  312. case ASN1UTIL_STEP_OVER_VALUE_OP:
  313. case ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP:
  314. pb += cbValue;
  315. cb -= cbValue;
  316. break;
  317. default:
  318. goto InvalidArg;
  319. }
  320. }
  321. lAllValues = (LONG)(pb - pbEncoded);
  322. assert((DWORD) lAllValues <= cbEncoded);
  323. CommonReturn:
  324. *pcValue = iValue;
  325. return lAllValues;
  326. ErrorReturn:
  327. lAllValues = -((LONG)(pb - pbEncoded)) - 1;
  328. goto CommonReturn;
  329. SET_ERROR(TooLittleData, ERROR_INVALID_DATA)
  330. SET_ERROR(InvalidTag, ERROR_INVALID_DATA)
  331. SET_ERROR(InvalidTagOrLength, ERROR_INVALID_DATA)
  332. SET_ERROR(InvalidArg, E_INVALIDARG)
  333. SET_ERROR(UnsupportedIndefiniteLength, ERROR_INVALID_DATA)
  334. SET_ERROR(NotAllowedIndefiniteLength, ERROR_INVALID_DATA)
  335. }
  336. static const BYTE rgbSeqTag[] = {ASN1UTIL_TAG_SEQ, 0};
  337. static const BYTE rgbSetTag[] = {ASN1UTIL_TAG_SET, 0};
  338. static const BYTE rgbOIDTag[] = {ASN1UTIL_TAG_OID, 0};
  339. static const BYTE rgbIntegerTag[] = {ASN1UTIL_TAG_INTEGER, 0};
  340. static const BYTE rgbBitStringTag[] = {ASN1UTIL_TAG_BITSTRING, 0};
  341. static const BYTE rgbConstructedContext0Tag[] =
  342. {ASN1UTIL_TAG_CONSTRUCTED_CONTEXT_0, 0};
  343. static const ASN1UTIL_EXTRACT_VALUE_PARA rgExtractSignedDataContentPara[] = {
  344. // 0 - ContentInfo ::= SEQUENCE {
  345. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  346. // 1 - contentType ContentType,
  347. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  348. ASN1UTIL_STEP_OVER_VALUE_OP, rgbOIDTag,
  349. // 2 - content [0] EXPLICIT ANY -- OPTIONAL
  350. ASN1UTIL_STEP_INTO_VALUE_OP, rgbConstructedContext0Tag,
  351. // 3 - SignedData ::= SEQUENCE {
  352. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  353. // 4 - version INTEGER,
  354. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  355. ASN1UTIL_STEP_OVER_VALUE_OP, rgbIntegerTag,
  356. // 5 - digestAlgorithms DigestAlgorithmIdentifiers,
  357. ASN1UTIL_STEP_OVER_VALUE_OP, rgbSetTag,
  358. // 6 - ContentInfo ::= SEQUENCE {
  359. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  360. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  361. // 7 - contentType ContentType,
  362. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  363. ASN1UTIL_STEP_OVER_VALUE_OP, rgbOIDTag,
  364. // 8 - content [0] EXPLICIT ANY -- OPTIONAL
  365. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  366. ASN1UTIL_STEP_INTO_VALUE_OP, rgbConstructedContext0Tag,
  367. };
  368. #define SIGNED_DATA_CONTENT_OUTER_OID_VALUE_INDEX 1
  369. #define SIGNED_DATA_CONTENT_VERSION_VALUE_INDEX 4
  370. #define SIGNED_DATA_CONTENT_INNER_OID_VALUE_INDEX 7
  371. #define SIGNED_DATA_CONTENT_INFO_SEQ_VALUE_INDEX 6
  372. #define SIGNED_DATA_CONTENT_CONTEXT_0_VALUE_INDEX 8
  373. #define SIGNED_DATA_CONTENT_VALUE_COUNT \
  374. (sizeof(rgExtractSignedDataContentPara) / \
  375. sizeof(rgExtractSignedDataContentPara[0]))
  376. static const ASN1UTIL_EXTRACT_VALUE_PARA rgExtractCertSignedContent[] = {
  377. // 0 - SignedContent ::= SEQUENCE {
  378. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  379. // 1 - toBeSigned NOCOPYANY,
  380. ASN1UTIL_RETURN_VALUE_BLOB_FLAG |
  381. ASN1UTIL_STEP_OVER_VALUE_OP, NULL,
  382. // 2 - algorithm AlgorithmIdentifier,
  383. ASN1UTIL_STEP_OVER_VALUE_OP, rgbSeqTag,
  384. // 3 - signature BITSTRING
  385. ASN1UTIL_STEP_OVER_VALUE_OP, rgbBitStringTag,
  386. };
  387. #define CERT_TO_BE_SIGNED_VALUE_INDEX 1
  388. #define CERT_SIGNED_CONTENT_VALUE_COUNT \
  389. (sizeof(rgExtractCertSignedContent) / \
  390. sizeof(rgExtractCertSignedContent[0]))
  391. static const ASN1UTIL_EXTRACT_VALUE_PARA rgExtractCertPublicKeyInfo[] = {
  392. // 0 - SignedContent ::= SEQUENCE {
  393. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  394. // 1 - CertificateToBeSigned ::= SEQUENCE {
  395. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  396. // 2 - version [0] CertificateVersion DEFAULT v1,
  397. ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP, rgbConstructedContext0Tag,
  398. // 3 - serialNumber CertificateSerialNumber,
  399. ASN1UTIL_STEP_OVER_VALUE_OP, rgbIntegerTag,
  400. // 4 - signature AlgorithmIdentifier,
  401. ASN1UTIL_STEP_OVER_VALUE_OP, rgbSeqTag,
  402. // 5 - issuer NOCOPYANY, -- really Name
  403. ASN1UTIL_STEP_OVER_VALUE_OP, rgbSeqTag,
  404. // 6 - validity Validity,
  405. ASN1UTIL_STEP_OVER_VALUE_OP, rgbSeqTag,
  406. // 7 - subject NOCOPYANY, -- really Name
  407. ASN1UTIL_STEP_OVER_VALUE_OP, rgbSeqTag,
  408. // 8 - subjectPublicKeyInfo SubjectPublicKeyInfo,
  409. ASN1UTIL_RETURN_VALUE_BLOB_FLAG |
  410. ASN1UTIL_STEP_OVER_VALUE_OP, rgbSeqTag
  411. };
  412. #define CERT_PUBLIC_KEY_INFO_VALUE_INDEX 8
  413. #define CERT_PUBLIC_KEY_INFO_VALUE_COUNT \
  414. (sizeof(rgExtractCertPublicKeyInfo) / \
  415. sizeof(rgExtractCertPublicKeyInfo[0]))
  416. // #define szOID_RSA_signedData "1.2.840.113549.1.7.2"
  417. static const BYTE rgbOIDSignedData[] =
  418. {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02};
  419. static const CRYPT_DER_BLOB EncodedOIDSignedData = {
  420. sizeof(rgbOIDSignedData), (BYTE *) rgbOIDSignedData
  421. };
  422. #ifdef CMS_PKCS7
  423. // #define szOID_RSA_Data "1.2.840.113549.1.7.1"
  424. static const BYTE rgbOIDData[] =
  425. {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01};
  426. static const CRYPT_DER_BLOB EncodedOIDData = {
  427. sizeof(rgbOIDData), (BYTE *) rgbOIDData
  428. };
  429. #endif // CMS_PKCS7
  430. // The encoded OID only includes the content octets. Excludes the tag and
  431. // length octets.
  432. static BOOL CompareEncodedOID(
  433. IN const CRYPT_DER_BLOB *pEncodedOID1,
  434. IN const CRYPT_DER_BLOB *pEncodedOID2
  435. )
  436. {
  437. if (pEncodedOID1->cbData == pEncodedOID2->cbData &&
  438. 0 == memcmp(pEncodedOID1->pbData, pEncodedOID2->pbData,
  439. pEncodedOID1->cbData))
  440. return TRUE;
  441. else
  442. return FALSE;
  443. }
  444. //+-------------------------------------------------------------------------
  445. // Skips past PKCS7 ASN.1 encoded values to get to the SignedData content.
  446. //
  447. // Checks that the outer ContentType has the SignedData OID and optionally
  448. // checks the inner SignedData content's ContentType.
  449. //
  450. // Returns:
  451. // success - the number of bytes skipped, >=0
  452. // failure - <0
  453. //
  454. // If the SignedData content is indefinite-length encoded,
  455. // *pcbContent is set to CMSG_INDEFINITE_LENGTH
  456. //--------------------------------------------------------------------------
  457. LONG
  458. WINAPI
  459. Asn1UtilExtractPKCS7SignedDataContent(
  460. IN const BYTE *pbEncoded,
  461. IN DWORD cbEncoded,
  462. IN OPTIONAL const CRYPT_DER_BLOB *pEncodedInnerOID,
  463. OUT DWORD *pcbContent,
  464. OUT const BYTE **ppbContent
  465. )
  466. {
  467. LONG lSkipped;
  468. DWORD cValue;
  469. CRYPT_DER_BLOB rgValueBlob[SIGNED_DATA_CONTENT_VALUE_COUNT];
  470. DWORD cbContent;
  471. const BYTE *pbContent;
  472. DWORD cbSeq;
  473. const BYTE *pbSeq;
  474. cValue = SIGNED_DATA_CONTENT_VALUE_COUNT;
  475. if (0 >= (lSkipped = Asn1UtilExtractValues(
  476. pbEncoded,
  477. cbEncoded,
  478. 0, // dwFlags
  479. &cValue,
  480. rgExtractSignedDataContentPara,
  481. rgValueBlob
  482. )))
  483. goto ExtractValuesError;
  484. pbContent = rgValueBlob[SIGNED_DATA_CONTENT_CONTEXT_0_VALUE_INDEX].pbData;
  485. cbContent = rgValueBlob[SIGNED_DATA_CONTENT_CONTEXT_0_VALUE_INDEX].cbData;
  486. // For definite-length encoded, check that the content wasn't
  487. // omitted.
  488. //
  489. // Note, for indefinite-length encoding, if the content was omitted,
  490. // we would have had a 0 tag instead of the CONTEXT_0 tag.
  491. cbSeq = rgValueBlob[SIGNED_DATA_CONTENT_INFO_SEQ_VALUE_INDEX].cbData;
  492. pbSeq = rgValueBlob[SIGNED_DATA_CONTENT_INFO_SEQ_VALUE_INDEX].pbData;
  493. if (CMSG_INDEFINITE_LENGTH != cbSeq && pbContent >= (pbSeq + cbSeq))
  494. goto NoSignedDataError;
  495. #ifdef CMS_PKCS7
  496. // For V3 SignedData, non Data types are wrapped, encapsulated with a
  497. // OCTET string
  498. if (1 == rgValueBlob[SIGNED_DATA_CONTENT_VERSION_VALUE_INDEX].cbData &&
  499. CMSG_SIGNED_DATA_V3 <=
  500. *(rgValueBlob[SIGNED_DATA_CONTENT_VERSION_VALUE_INDEX].pbData)
  501. &&
  502. !CompareEncodedOID(
  503. &rgValueBlob[SIGNED_DATA_CONTENT_INNER_OID_VALUE_INDEX],
  504. &EncodedOIDData)
  505. &&
  506. 0 != cbContent && ASN1UTIL_TAG_OCTETSTRING == *pbContent
  507. ) {
  508. LONG lTagLength;
  509. const BYTE *pbInner;
  510. DWORD cbInner;
  511. // Advance past the outer OCTET wrapper
  512. lTagLength = Asn1UtilExtractContent(
  513. pbContent,
  514. cbEncoded - lSkipped,
  515. &cbInner,
  516. &pbInner
  517. );
  518. if (0 < lTagLength) {
  519. lSkipped += lTagLength;
  520. cbContent = cbInner;
  521. pbContent = pbInner;
  522. }
  523. }
  524. #endif
  525. if (CMSG_INDEFINITE_LENGTH == cbContent) {
  526. // Extract the pbContent and attempt to get its definite length
  527. LONG lTagLength;
  528. const BYTE *pbInner;
  529. DWORD cbInner;
  530. lTagLength = Asn1UtilExtractContent(
  531. pbContent,
  532. cbEncoded - lSkipped,
  533. &cbInner,
  534. &pbInner
  535. );
  536. if (0 < lTagLength && CMSG_INDEFINITE_LENGTH != cbInner)
  537. cbContent = cbInner + lTagLength;
  538. }
  539. // Verify that the outer ContentType is SignedData and the inner
  540. // ContentType is the specified type
  541. if (!CompareEncodedOID(
  542. &rgValueBlob[SIGNED_DATA_CONTENT_OUTER_OID_VALUE_INDEX],
  543. &EncodedOIDSignedData
  544. ))
  545. goto NotSignedDataContentType;
  546. if (pEncodedInnerOID && !CompareEncodedOID(
  547. &rgValueBlob[SIGNED_DATA_CONTENT_INNER_OID_VALUE_INDEX],
  548. pEncodedInnerOID
  549. ))
  550. goto UnexpectedInnerContentTypeError;
  551. *pcbContent = cbContent;
  552. *ppbContent = pbContent;
  553. CommonReturn:
  554. return lSkipped;
  555. ErrorReturn:
  556. if (0 <= lSkipped)
  557. lSkipped = -lSkipped - 1;
  558. *pcbContent = 0;
  559. *ppbContent = NULL;
  560. goto CommonReturn;
  561. TRACE_ERROR(ExtractValuesError)
  562. SET_ERROR(NoSignedDataError, ERROR_INVALID_DATA)
  563. SET_ERROR(NotSignedDataContentType, ERROR_INVALID_DATA)
  564. SET_ERROR(UnexpectedInnerContentTypeError, ERROR_INVALID_DATA)
  565. }
  566. //+-------------------------------------------------------------------------
  567. // Verifies this is a certificate ASN.1 encoded signed content.
  568. // Returns the pointer to and length of the ToBeSigned content.
  569. //
  570. // Returns an error if the ToBeSigned content isn't definite length
  571. // encoded.
  572. //--------------------------------------------------------------------------
  573. BOOL
  574. WINAPI
  575. Asn1UtilExtractCertificateToBeSignedContent(
  576. IN const BYTE *pbEncoded,
  577. IN DWORD cbEncoded,
  578. OUT DWORD *pcbContent,
  579. OUT const BYTE **ppbContent
  580. )
  581. {
  582. BOOL fResult;
  583. DWORD cValue;
  584. CRYPT_DER_BLOB rgValueBlob[CERT_SIGNED_CONTENT_VALUE_COUNT];
  585. cValue = CERT_SIGNED_CONTENT_VALUE_COUNT;
  586. if (0 >= Asn1UtilExtractValues(
  587. pbEncoded,
  588. cbEncoded,
  589. ASN1UTIL_DEFINITE_LENGTH_FLAG,
  590. &cValue,
  591. rgExtractCertSignedContent,
  592. rgValueBlob
  593. ))
  594. goto ExtractValuesError;
  595. *ppbContent = rgValueBlob[CERT_TO_BE_SIGNED_VALUE_INDEX].pbData;
  596. *pcbContent = rgValueBlob[CERT_TO_BE_SIGNED_VALUE_INDEX].cbData;
  597. fResult = TRUE;
  598. CommonReturn:
  599. return fResult;
  600. ErrorReturn:
  601. fResult = FALSE;
  602. *ppbContent = NULL;
  603. *pcbContent = 0;
  604. goto CommonReturn;
  605. TRACE_ERROR(ExtractValuesError)
  606. }
  607. //+-------------------------------------------------------------------------
  608. // Returns the pointer to and length of the SubjectPublicKeyInfo value in
  609. // a signed and encoded X.509 certificate.
  610. //
  611. // Returns an error if the value isn't definite length encoded.
  612. //--------------------------------------------------------------------------
  613. BOOL
  614. WINAPI
  615. Asn1UtilExtractCertificatePublicKeyInfo(
  616. IN const BYTE *pbEncoded,
  617. IN DWORD cbEncoded,
  618. OUT DWORD *pcbPublicKeyInfo,
  619. OUT const BYTE **ppbPublicKeyInfo
  620. )
  621. {
  622. BOOL fResult;
  623. DWORD cValue;
  624. CRYPT_DER_BLOB rgValueBlob[CERT_PUBLIC_KEY_INFO_VALUE_COUNT];
  625. cValue = CERT_PUBLIC_KEY_INFO_VALUE_COUNT;
  626. if (0 >= Asn1UtilExtractValues(
  627. pbEncoded,
  628. cbEncoded,
  629. ASN1UTIL_DEFINITE_LENGTH_FLAG,
  630. &cValue,
  631. rgExtractCertPublicKeyInfo,
  632. rgValueBlob
  633. ))
  634. goto ExtractValuesError;
  635. *ppbPublicKeyInfo = rgValueBlob[CERT_PUBLIC_KEY_INFO_VALUE_INDEX].pbData;
  636. *pcbPublicKeyInfo = rgValueBlob[CERT_PUBLIC_KEY_INFO_VALUE_INDEX].cbData;
  637. fResult = TRUE;
  638. CommonReturn:
  639. return fResult;
  640. ErrorReturn:
  641. fResult = FALSE;
  642. *ppbPublicKeyInfo = NULL;
  643. *pcbPublicKeyInfo = 0;
  644. goto CommonReturn;
  645. TRACE_ERROR(ExtractValuesError)
  646. }
  647. // Special RDN containing the KEY_ID. Its value type is CERT_RDN_OCTET_STRING.
  648. //#define szOID_KEYID_RDN "1.3.6.1.4.1.311.10.7.1"
  649. static const BYTE rgbOIDKeyIdRDN[] =
  650. {0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0A, 0x07, 0x01};
  651. static const CRYPT_DER_BLOB EncodedOIDKeyIdRDN = {
  652. sizeof(rgbOIDKeyIdRDN), (BYTE *) rgbOIDKeyIdRDN
  653. };
  654. static const BYTE rgbOctetStringTag[] = {ASN1UTIL_TAG_OCTETSTRING, 0};
  655. static const ASN1UTIL_EXTRACT_VALUE_PARA rgExtractNameKeyIdRDNPara[] = {
  656. // 0 - Name ::= SEQUENCE OF RelativeDistinguishedName
  657. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  658. // 1 - RelativeDistinguishedName ::= SET OF AttributeTypeValue
  659. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSetTag,
  660. // 2 - AttributeTypeValue ::= SEQUENCE
  661. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  662. // 3 - type EncodedObjectID,
  663. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  664. ASN1UTIL_STEP_OVER_VALUE_OP, rgbOIDTag,
  665. // 4 - value NOCOPYANY
  666. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  667. ASN1UTIL_STEP_OVER_VALUE_OP, rgbOctetStringTag,
  668. };
  669. #define NAME_KEYID_RDN_OID_VALUE_INDEX 3
  670. #define NAME_KEYID_RDN_OCTET_VALUE_INDEX 4
  671. #define NAME_KEYID_RDN_VALUE_COUNT \
  672. (sizeof(rgExtractNameKeyIdRDNPara) / \
  673. sizeof(rgExtractNameKeyIdRDNPara[0]))
  674. //+-------------------------------------------------------------------------
  675. // If the Issuer and SerialNumber in the CERT_INFO contains a special
  676. // KeyID RDN attribute returns TRUE with pKeyId's cbData and pbData updated
  677. // with the RDN attribute's OCTET_STRING value. Otherwise, returns FALSE.
  678. //--------------------------------------------------------------------------
  679. BOOL
  680. WINAPI
  681. Asn1UtilExtractKeyIdFromCertInfo(
  682. IN PCERT_INFO pCertInfo,
  683. OUT PCRYPT_HASH_BLOB pKeyId
  684. )
  685. {
  686. DWORD cValue;
  687. CRYPT_DER_BLOB rgValueBlob[NAME_KEYID_RDN_VALUE_COUNT];
  688. if (0 == pCertInfo->SerialNumber.cbData ||
  689. 0 != *pCertInfo->SerialNumber.pbData)
  690. goto NoKeyId;
  691. cValue = NAME_KEYID_RDN_VALUE_COUNT;
  692. if (0 > Asn1UtilExtractValues(
  693. pCertInfo->Issuer.pbData,
  694. pCertInfo->Issuer.cbData,
  695. 0, // dwFlags
  696. &cValue,
  697. rgExtractNameKeyIdRDNPara,
  698. rgValueBlob
  699. ))
  700. goto NoKeyId;
  701. if (!CompareEncodedOID(
  702. &rgValueBlob[NAME_KEYID_RDN_OID_VALUE_INDEX],
  703. &EncodedOIDKeyIdRDN))
  704. goto NoKeyId;
  705. if (CMSG_INDEFINITE_LENGTH ==
  706. rgValueBlob[NAME_KEYID_RDN_OCTET_VALUE_INDEX].cbData)
  707. goto NoKeyId;
  708. pKeyId->pbData = rgValueBlob[NAME_KEYID_RDN_OCTET_VALUE_INDEX].pbData;
  709. pKeyId->cbData = rgValueBlob[NAME_KEYID_RDN_OCTET_VALUE_INDEX].cbData;
  710. return TRUE;
  711. NoKeyId:
  712. pKeyId->pbData = NULL;
  713. pKeyId->cbData = 0;
  714. return FALSE;
  715. }