/security/nss/lib/pkcs12/p12dec.c

http://github.com/zpao/v8monkey · C · 696 lines · 458 code · 93 blank · 145 comment · 147 complexity · e4bebf1f7cae583c766571003022c3e9 MD5 · raw file

  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is the Netscape security libraries.
  15. *
  16. * The Initial Developer of the Original Code is
  17. * Netscape Communications Corporation.
  18. * Portions created by the Initial Developer are Copyright (C) 1994-2000
  19. * the Initial Developer. All Rights Reserved.
  20. *
  21. * Contributor(s):
  22. *
  23. * Alternatively, the contents of this file may be used under the terms of
  24. * either the GNU General Public License Version 2 or later (the "GPL"), or
  25. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26. * in which case the provisions of the GPL or the LGPL are applicable instead
  27. * of those above. If you wish to allow use of your version of this file only
  28. * under the terms of either the GPL or the LGPL, and not to allow others to
  29. * use your version of this file under the terms of the MPL, indicate your
  30. * decision by deleting the provisions above and replace them with the notice
  31. * and other provisions required by the GPL or the LGPL. If you do not delete
  32. * the provisions above, a recipient may use your version of this file under
  33. * the terms of any one of the MPL, the GPL or the LGPL.
  34. *
  35. * ***** END LICENSE BLOCK ***** */
  36. #include "pkcs12.h"
  37. #include "plarena.h"
  38. #include "secpkcs7.h"
  39. #include "p12local.h"
  40. #include "secoid.h"
  41. #include "secitem.h"
  42. #include "secport.h"
  43. #include "secasn1.h"
  44. #include "secder.h"
  45. #include "secerr.h"
  46. #include "cert.h"
  47. #include "certdb.h"
  48. #include "p12plcy.h"
  49. #include "p12.h"
  50. #include "secpkcs5.h"
  51. /* PFX extraction and validation routines */
  52. /* decode the DER encoded PFX item. if unable to decode, check to see if it
  53. * is an older PFX item. If that fails, assume the file was not a valid
  54. * pfx file.
  55. * the returned pfx structure should be destroyed using SEC_PKCS12DestroyPFX
  56. */
  57. static SEC_PKCS12PFXItem *
  58. sec_pkcs12_decode_pfx(SECItem *der_pfx)
  59. {
  60. SEC_PKCS12PFXItem *pfx;
  61. SECStatus rv;
  62. if(der_pfx == NULL) {
  63. return NULL;
  64. }
  65. /* allocate the space for a new PFX item */
  66. pfx = sec_pkcs12_new_pfx();
  67. if(pfx == NULL) {
  68. return NULL;
  69. }
  70. rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate,
  71. der_pfx);
  72. /* if a failure occurred, check for older version...
  73. * we also get rid of the old pfx structure, because we don't
  74. * know where it failed and what data in may contain
  75. */
  76. if(rv != SECSuccess) {
  77. SEC_PKCS12DestroyPFX(pfx);
  78. pfx = sec_pkcs12_new_pfx();
  79. if(pfx == NULL) {
  80. return NULL;
  81. }
  82. rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate_OLD,
  83. der_pfx);
  84. if(rv != SECSuccess) {
  85. PORT_SetError(SEC_ERROR_PKCS12_DECODING_PFX);
  86. PORT_FreeArena(pfx->poolp, PR_TRUE);
  87. return NULL;
  88. }
  89. pfx->old = PR_TRUE;
  90. SGN_CopyDigestInfo(pfx->poolp, &pfx->macData.safeMac, &pfx->old_safeMac);
  91. SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, &pfx->old_macSalt);
  92. } else {
  93. pfx->old = PR_FALSE;
  94. }
  95. /* convert bit string from bits to bytes */
  96. pfx->macData.macSalt.len /= 8;
  97. return pfx;
  98. }
  99. /* validate the integrity MAC used in the PFX. The MAC is generated
  100. * per the PKCS 12 document. If the MAC is incorrect, it is most likely
  101. * due to an invalid password.
  102. * pwitem is the integrity password
  103. * pfx is the decoded pfx item
  104. */
  105. static PRBool
  106. sec_pkcs12_check_pfx_mac(SEC_PKCS12PFXItem *pfx,
  107. SECItem *pwitem)
  108. {
  109. SECItem *key = NULL, *mac = NULL, *data = NULL;
  110. SECItem *vpwd = NULL;
  111. SECOidTag algorithm;
  112. PRBool ret = PR_FALSE;
  113. if(pfx == NULL) {
  114. return PR_FALSE;
  115. }
  116. algorithm = SECOID_GetAlgorithmTag(&pfx->macData.safeMac.digestAlgorithm);
  117. switch(algorithm) {
  118. /* only SHA1 hashing supported as a MACing algorithm */
  119. case SEC_OID_SHA1:
  120. if(pfx->old == PR_FALSE) {
  121. pfx->swapUnicode = PR_FALSE;
  122. }
  123. recheckUnicodePassword:
  124. vpwd = sec_pkcs12_create_virtual_password(pwitem,
  125. &pfx->macData.macSalt,
  126. pfx->swapUnicode);
  127. if(vpwd == NULL) {
  128. return PR_FALSE;
  129. }
  130. key = sec_pkcs12_generate_key_from_password(algorithm,
  131. &pfx->macData.macSalt,
  132. (pfx->old ? pwitem : vpwd));
  133. /* free vpwd only for newer PFX */
  134. if(vpwd) {
  135. SECITEM_ZfreeItem(vpwd, PR_TRUE);
  136. }
  137. if(key == NULL) {
  138. return PR_FALSE;
  139. }
  140. data = SEC_PKCS7GetContent(&pfx->authSafe);
  141. if(data == NULL) {
  142. break;
  143. }
  144. /* check MAC */
  145. mac = sec_pkcs12_generate_mac(key, data, pfx->old);
  146. ret = PR_TRUE;
  147. if(mac) {
  148. SECItem *safeMac = &pfx->macData.safeMac.digest;
  149. if(SECITEM_CompareItem(mac, safeMac) != SECEqual) {
  150. /* if we encounter an invalid mac, lets invert the
  151. * password in case of unicode changes
  152. */
  153. if(((!pfx->old) && pfx->swapUnicode) || (pfx->old)){
  154. PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
  155. ret = PR_FALSE;
  156. } else {
  157. SECITEM_ZfreeItem(mac, PR_TRUE);
  158. pfx->swapUnicode = PR_TRUE;
  159. goto recheckUnicodePassword;
  160. }
  161. }
  162. SECITEM_ZfreeItem(mac, PR_TRUE);
  163. } else {
  164. ret = PR_FALSE;
  165. }
  166. break;
  167. default:
  168. PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM);
  169. ret = PR_FALSE;
  170. break;
  171. }
  172. /* let success fall through */
  173. if(key != NULL)
  174. SECITEM_ZfreeItem(key, PR_TRUE);
  175. return ret;
  176. }
  177. /* check the validity of the pfx structure. we currently only support
  178. * password integrity mode, so we check the MAC.
  179. */
  180. static PRBool
  181. sec_pkcs12_validate_pfx(SEC_PKCS12PFXItem *pfx,
  182. SECItem *pwitem)
  183. {
  184. SECOidTag contentType;
  185. contentType = SEC_PKCS7ContentType(&pfx->authSafe);
  186. switch(contentType)
  187. {
  188. case SEC_OID_PKCS7_DATA:
  189. return sec_pkcs12_check_pfx_mac(pfx, pwitem);
  190. break;
  191. case SEC_OID_PKCS7_SIGNED_DATA:
  192. default:
  193. PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE);
  194. break;
  195. }
  196. return PR_FALSE;
  197. }
  198. /* decode and return the valid PFX. if the PFX item is not valid,
  199. * NULL is returned.
  200. */
  201. static SEC_PKCS12PFXItem *
  202. sec_pkcs12_get_pfx(SECItem *pfx_data,
  203. SECItem *pwitem)
  204. {
  205. SEC_PKCS12PFXItem *pfx;
  206. PRBool valid_pfx;
  207. if((pfx_data == NULL) || (pwitem == NULL)) {
  208. return NULL;
  209. }
  210. pfx = sec_pkcs12_decode_pfx(pfx_data);
  211. if(pfx == NULL) {
  212. return NULL;
  213. }
  214. valid_pfx = sec_pkcs12_validate_pfx(pfx, pwitem);
  215. if(valid_pfx != PR_TRUE) {
  216. SEC_PKCS12DestroyPFX(pfx);
  217. pfx = NULL;
  218. }
  219. return pfx;
  220. }
  221. /* authenticated safe decoding, validation, and access routines
  222. */
  223. /* convert dogbert beta 3 authenticated safe structure to a post
  224. * beta three structure, so that we don't have to change more routines.
  225. */
  226. static SECStatus
  227. sec_pkcs12_convert_old_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe)
  228. {
  229. SEC_PKCS12Baggage *baggage;
  230. SEC_PKCS12BaggageItem *bag;
  231. SECStatus rv = SECSuccess;
  232. if(asafe->old_baggage.espvks == NULL) {
  233. /* XXX should the ASN1 engine produce a single NULL element list
  234. * rather than setting the pointer to NULL?
  235. * There is no need to return an error -- assume that the list
  236. * was empty.
  237. */
  238. return SECSuccess;
  239. }
  240. baggage = sec_pkcs12_create_baggage(asafe->poolp);
  241. if(!baggage) {
  242. return SECFailure;
  243. }
  244. bag = sec_pkcs12_create_external_bag(baggage);
  245. if(!bag) {
  246. return SECFailure;
  247. }
  248. PORT_Memcpy(&asafe->baggage, baggage, sizeof(SEC_PKCS12Baggage));
  249. /* if there are shrouded keys, append them to the bag */
  250. rv = SECSuccess;
  251. if(asafe->old_baggage.espvks[0] != NULL) {
  252. int nEspvk = 0;
  253. rv = SECSuccess;
  254. while((asafe->old_baggage.espvks[nEspvk] != NULL) &&
  255. (rv == SECSuccess)) {
  256. rv = sec_pkcs12_append_shrouded_key(bag,
  257. asafe->old_baggage.espvks[nEspvk]);
  258. nEspvk++;
  259. }
  260. }
  261. return rv;
  262. }
  263. /* decodes the authenticated safe item. a return of NULL indicates
  264. * an error. however, the error will have occurred either in memory
  265. * allocation or in decoding the authenticated safe.
  266. *
  267. * if an old PFX item has been found, we want to convert the
  268. * old authenticated safe to the new one.
  269. */
  270. static SEC_PKCS12AuthenticatedSafe *
  271. sec_pkcs12_decode_authenticated_safe(SEC_PKCS12PFXItem *pfx)
  272. {
  273. SECItem *der_asafe = NULL;
  274. SEC_PKCS12AuthenticatedSafe *asafe = NULL;
  275. SECStatus rv;
  276. if(pfx == NULL) {
  277. return NULL;
  278. }
  279. der_asafe = SEC_PKCS7GetContent(&pfx->authSafe);
  280. if(der_asafe == NULL) {
  281. /* XXX set error ? */
  282. goto loser;
  283. }
  284. asafe = sec_pkcs12_new_asafe(pfx->poolp);
  285. if(asafe == NULL) {
  286. goto loser;
  287. }
  288. if(pfx->old == PR_FALSE) {
  289. rv = SEC_ASN1DecodeItem(pfx->poolp, asafe,
  290. SEC_PKCS12AuthenticatedSafeTemplate,
  291. der_asafe);
  292. asafe->old = PR_FALSE;
  293. asafe->swapUnicode = pfx->swapUnicode;
  294. } else {
  295. /* handle beta exported files */
  296. rv = SEC_ASN1DecodeItem(pfx->poolp, asafe,
  297. SEC_PKCS12AuthenticatedSafeTemplate_OLD,
  298. der_asafe);
  299. asafe->safe = &(asafe->old_safe);
  300. rv = sec_pkcs12_convert_old_auth_safe(asafe);
  301. asafe->old = PR_TRUE;
  302. }
  303. if(rv != SECSuccess) {
  304. goto loser;
  305. }
  306. asafe->poolp = pfx->poolp;
  307. return asafe;
  308. loser:
  309. return NULL;
  310. }
  311. /* validates the safe within the authenticated safe item.
  312. * in order to be valid:
  313. * 1. the privacy salt must be present
  314. * 2. the encryption algorithm must be supported (including
  315. * export policy)
  316. * PR_FALSE indicates an error, PR_TRUE indicates a valid safe
  317. */
  318. static PRBool
  319. sec_pkcs12_validate_encrypted_safe(SEC_PKCS12AuthenticatedSafe *asafe)
  320. {
  321. PRBool valid = PR_FALSE;
  322. SECAlgorithmID *algid;
  323. if(asafe == NULL) {
  324. return PR_FALSE;
  325. }
  326. /* if mode is password privacy, then privacySalt is assumed
  327. * to be non-zero.
  328. */
  329. if(asafe->privacySalt.len != 0) {
  330. valid = PR_TRUE;
  331. asafe->privacySalt.len /= 8;
  332. } else {
  333. PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
  334. return PR_FALSE;
  335. }
  336. /* until spec changes, content will have between 2 and 8 bytes depending
  337. * upon the algorithm used if certs are unencrypted...
  338. * also want to support case where content is empty -- which we produce
  339. */
  340. if(SEC_PKCS7IsContentEmpty(asafe->safe, 8) == PR_TRUE) {
  341. asafe->emptySafe = PR_TRUE;
  342. return PR_TRUE;
  343. }
  344. asafe->emptySafe = PR_FALSE;
  345. /* make sure that a pbe algorithm is being used */
  346. algid = SEC_PKCS7GetEncryptionAlgorithm(asafe->safe);
  347. if(algid != NULL) {
  348. if(SEC_PKCS5IsAlgorithmPBEAlg(algid)) {
  349. valid = SEC_PKCS12DecryptionAllowed(algid);
  350. if(valid == PR_FALSE) {
  351. PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM);
  352. }
  353. } else {
  354. PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM);
  355. valid = PR_FALSE;
  356. }
  357. } else {
  358. valid = PR_FALSE;
  359. PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM);
  360. }
  361. return valid;
  362. }
  363. /* validates authenticates safe:
  364. * 1. checks that the version is supported
  365. * 2. checks that only password privacy mode is used (currently)
  366. * 3. further, makes sure safe has appropriate policies per above function
  367. * PR_FALSE indicates failure.
  368. */
  369. static PRBool
  370. sec_pkcs12_validate_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe)
  371. {
  372. PRBool valid = PR_TRUE;
  373. SECOidTag safe_type;
  374. int version;
  375. if(asafe == NULL) {
  376. return PR_FALSE;
  377. }
  378. /* check version, since it is default it may not be present.
  379. * therefore, assume ok
  380. */
  381. if((asafe->version.len > 0) && (asafe->old == PR_FALSE)) {
  382. version = DER_GetInteger(&asafe->version);
  383. if(version > SEC_PKCS12_PFX_VERSION) {
  384. PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION);
  385. return PR_FALSE;
  386. }
  387. }
  388. /* validate password mode is being used */
  389. safe_type = SEC_PKCS7ContentType(asafe->safe);
  390. switch(safe_type)
  391. {
  392. case SEC_OID_PKCS7_ENCRYPTED_DATA:
  393. valid = sec_pkcs12_validate_encrypted_safe(asafe);
  394. break;
  395. case SEC_OID_PKCS7_ENVELOPED_DATA:
  396. default:
  397. PORT_SetError(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE);
  398. valid = PR_FALSE;
  399. break;
  400. }
  401. return valid;
  402. }
  403. /* retrieves the authenticated safe item from the PFX item
  404. * before returning the authenticated safe, the validity of the
  405. * authenticated safe is checked and if valid, returned.
  406. * a return of NULL indicates that an error occurred.
  407. */
  408. static SEC_PKCS12AuthenticatedSafe *
  409. sec_pkcs12_get_auth_safe(SEC_PKCS12PFXItem *pfx)
  410. {
  411. SEC_PKCS12AuthenticatedSafe *asafe;
  412. PRBool valid_safe;
  413. if(pfx == NULL) {
  414. return NULL;
  415. }
  416. asafe = sec_pkcs12_decode_authenticated_safe(pfx);
  417. if(asafe == NULL) {
  418. return NULL;
  419. }
  420. valid_safe = sec_pkcs12_validate_auth_safe(asafe);
  421. if(valid_safe != PR_TRUE) {
  422. asafe = NULL;
  423. } else if(asafe) {
  424. asafe->baggage.poolp = asafe->poolp;
  425. }
  426. return asafe;
  427. }
  428. /* decrypts the authenticated safe.
  429. * a return of anything but SECSuccess indicates an error. the
  430. * password is not known to be valid until the call to the
  431. * function sec_pkcs12_get_safe_contents. If decoding the safe
  432. * fails, it is assumed the password was incorrect and the error
  433. * is set then. any failure here is assumed to be due to
  434. * internal problems in SEC_PKCS7DecryptContents or below.
  435. */
  436. static SECStatus
  437. sec_pkcs12_decrypt_auth_safe(SEC_PKCS12AuthenticatedSafe *asafe,
  438. SECItem *pwitem,
  439. void *wincx)
  440. {
  441. SECStatus rv = SECFailure;
  442. SECItem *vpwd = NULL;
  443. if((asafe == NULL) || (pwitem == NULL)) {
  444. return SECFailure;
  445. }
  446. if(asafe->old == PR_FALSE) {
  447. vpwd = sec_pkcs12_create_virtual_password(pwitem, &asafe->privacySalt,
  448. asafe->swapUnicode);
  449. if(vpwd == NULL) {
  450. return SECFailure;
  451. }
  452. }
  453. rv = SEC_PKCS7DecryptContents(asafe->poolp, asafe->safe,
  454. (asafe->old ? pwitem : vpwd), wincx);
  455. if(asafe->old == PR_FALSE) {
  456. SECITEM_ZfreeItem(vpwd, PR_TRUE);
  457. }
  458. return rv;
  459. }
  460. /* extract the safe from the authenticated safe.
  461. * if we are unable to decode the safe, then it is likely that the
  462. * safe has not been decrypted or the password used to decrypt
  463. * the safe was invalid. we assume that the password was invalid and
  464. * set an error accordingly.
  465. * a return of NULL indicates that an error occurred.
  466. */
  467. static SEC_PKCS12SafeContents *
  468. sec_pkcs12_get_safe_contents(SEC_PKCS12AuthenticatedSafe *asafe)
  469. {
  470. SECItem *src = NULL;
  471. SEC_PKCS12SafeContents *safe = NULL;
  472. SECStatus rv = SECFailure;
  473. if(asafe == NULL) {
  474. return NULL;
  475. }
  476. safe = (SEC_PKCS12SafeContents *)PORT_ArenaZAlloc(asafe->poolp,
  477. sizeof(SEC_PKCS12SafeContents));
  478. if(safe == NULL) {
  479. return NULL;
  480. }
  481. safe->poolp = asafe->poolp;
  482. safe->old = asafe->old;
  483. safe->swapUnicode = asafe->swapUnicode;
  484. src = SEC_PKCS7GetContent(asafe->safe);
  485. if(src != NULL) {
  486. const SEC_ASN1Template *theTemplate;
  487. if(asafe->old != PR_TRUE) {
  488. theTemplate = SEC_PKCS12SafeContentsTemplate;
  489. } else {
  490. theTemplate = SEC_PKCS12SafeContentsTemplate_OLD;
  491. }
  492. rv = SEC_ASN1DecodeItem(asafe->poolp, safe, theTemplate, src);
  493. /* if we could not decode the item, password was probably invalid */
  494. if(rv != SECSuccess) {
  495. safe = NULL;
  496. PORT_SetError(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT);
  497. }
  498. } else {
  499. PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
  500. rv = SECFailure;
  501. }
  502. return safe;
  503. }
  504. /* import PFX item
  505. * der_pfx is the der encoded pfx structure
  506. * pbef and pbearg are the integrity/encryption password call back
  507. * ncCall is the nickname collision calllback
  508. * slot is the destination token
  509. * wincx window handler
  510. *
  511. * on error, error code set and SECFailure returned
  512. */
  513. SECStatus
  514. SEC_PKCS12PutPFX(SECItem *der_pfx, SECItem *pwitem,
  515. SEC_PKCS12NicknameCollisionCallback ncCall,
  516. PK11SlotInfo *slot,
  517. void *wincx)
  518. {
  519. SEC_PKCS12PFXItem *pfx;
  520. SEC_PKCS12AuthenticatedSafe *asafe;
  521. SEC_PKCS12SafeContents *safe_contents = NULL;
  522. SECStatus rv;
  523. if(!der_pfx || !pwitem || !slot) {
  524. return SECFailure;
  525. }
  526. /* decode and validate each section */
  527. rv = SECFailure;
  528. pfx = sec_pkcs12_get_pfx(der_pfx, pwitem);
  529. if(pfx != NULL) {
  530. asafe = sec_pkcs12_get_auth_safe(pfx);
  531. if(asafe != NULL) {
  532. /* decrypt safe -- only if not empty */
  533. if(asafe->emptySafe != PR_TRUE) {
  534. rv = sec_pkcs12_decrypt_auth_safe(asafe, pwitem, wincx);
  535. if(rv == SECSuccess) {
  536. safe_contents = sec_pkcs12_get_safe_contents(asafe);
  537. if(safe_contents == NULL) {
  538. rv = SECFailure;
  539. }
  540. }
  541. } else {
  542. safe_contents = sec_pkcs12_create_safe_contents(asafe->poolp);
  543. if(safe_contents == NULL) {
  544. rv = SECFailure;
  545. } else {
  546. safe_contents->swapUnicode = pfx->swapUnicode;
  547. rv = SECSuccess;
  548. }
  549. }
  550. /* get safe contents and begin import */
  551. if(rv == SECSuccess) {
  552. SEC_PKCS12DecoderContext *p12dcx;
  553. p12dcx = sec_PKCS12ConvertOldSafeToNew(pfx->poolp, slot,
  554. pfx->swapUnicode,
  555. pwitem, wincx, safe_contents,
  556. &asafe->baggage);
  557. if(!p12dcx) {
  558. rv = SECFailure;
  559. goto loser;
  560. }
  561. if(SEC_PKCS12DecoderValidateBags(p12dcx, ncCall)
  562. != SECSuccess) {
  563. rv = SECFailure;
  564. goto loser;
  565. }
  566. rv = SEC_PKCS12DecoderImportBags(p12dcx);
  567. }
  568. }
  569. }
  570. loser:
  571. if(pfx) {
  572. SEC_PKCS12DestroyPFX(pfx);
  573. }
  574. return rv;
  575. }
  576. PRBool
  577. SEC_PKCS12ValidData(char *buf, int bufLen, long int totalLength)
  578. {
  579. int lengthLength;
  580. PRBool valid = PR_FALSE;
  581. if(buf == NULL) {
  582. return PR_FALSE;
  583. }
  584. /* check for constructed sequence identifier tag */
  585. if(*buf == (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) {
  586. totalLength--; /* header byte taken care of */
  587. buf++;
  588. lengthLength = (long int)SEC_ASN1LengthLength(totalLength - 1);
  589. if(totalLength > 0x7f) {
  590. lengthLength--;
  591. *buf &= 0x7f; /* remove bit 8 indicator */
  592. if((*buf - (char)lengthLength) == 0) {
  593. valid = PR_TRUE;
  594. }
  595. } else {
  596. lengthLength--;
  597. if((*buf - (char)lengthLength) == 0) {
  598. valid = PR_TRUE;
  599. }
  600. }
  601. }
  602. return valid;
  603. }