security/nss/lib/pkcs12/p12dec.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial