PageRenderTime 82ms CodeModel.GetById 30ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 0ms

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

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