Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / security / nss / lib / pki1 / atav.c
blob2755c2082711d49d187aa6aeb1855f8ba98a91b6
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
14 * The Original Code is the Netscape security libraries.
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.
21 * Contributor(s):
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.
35 * ***** END LICENSE BLOCK ***** */
37 #ifdef DEBUG
38 static const char CVS_ID[] = "@(#) $RCSfile: atav.c,v $ $Revision: 1.8 $ $Date: 2005/01/20 02:25:49 $";
39 #endif /* DEBUG */
42 * atav.c
44 * This file contains the implementation of the PKIX part-1 object
45 * AttributeTypeAndValue.
48 #ifndef NSSBASE_H
49 #include "nssbase.h"
50 #endif /* NSSBASE_H */
52 #ifndef ASN1_H
53 #include "asn1.h"
54 #endif /* ASN1_H */
56 #ifndef PKI1_H
57 #include "pki1.h"
58 #endif /* PKI1_H */
61 * AttributeTypeAndValue
63 * From draft-ietf-pkix-ipki-part1-10:
65 * AttributeTypeAndValue ::= SEQUENCE {
66 * type ATTRIBUTE.&id ({SupportedAttributes}),
67 * value ATTRIBUTE.&Type ({SupportedAttributes}{@type})}
69 * -- ATTRIBUTE information object class specification
70 * -- Note: This has been greatly simplified for PKIX !!
72 * ATTRIBUTE ::= CLASS {
73 * &Type,
74 * &id OBJECT IDENTIFIER UNIQUE }
75 * WITH SYNTAX {
76 * WITH SYNTAX &Type ID &id }
78 * What this means is that the "type" of the value is determined by
79 * the value of the oid. If we hide the structure, our accessors
80 * can (at least in debug builds) assert value semantics beyond what
81 * the compiler can provide. Since these things are only used in
82 * RelativeDistinguishedNames, and since RDNs always contain a SET
83 * of these things, we don't lose anything by hiding the structure
84 * (and its size).
87 struct NSSATAVStr {
88 NSSBER ber;
89 const NSSOID *oid;
90 NSSUTF8 *value;
91 nssStringType stringForm;
95 * NSSATAV
97 * The public "methods" regarding this "object" are:
99 * NSSATAV_CreateFromBER -- constructor
100 * NSSATAV_CreateFromUTF8 -- constructor
101 * NSSATAV_Create -- constructor
103 * NSSATAV_Destroy
104 * NSSATAV_GetDEREncoding
105 * NSSATAV_GetUTF8Encoding
106 * NSSATAV_GetType
107 * NSSATAV_GetValue
108 * NSSATAV_Compare
109 * NSSATAV_Duplicate
111 * The non-public "methods" regarding this "object" are:
113 * nssATAV_CreateFromBER -- constructor
114 * nssATAV_CreateFromUTF8 -- constructor
115 * nssATAV_Create -- constructor
117 * nssATAV_Destroy
118 * nssATAV_GetDEREncoding
119 * nssATAV_GetUTF8Encoding
120 * nssATAV_GetType
121 * nssATAV_GetValue
122 * nssATAV_Compare
123 * nssATAV_Duplicate
125 * In debug builds, the following non-public call is also available:
127 * nssATAV_verifyPointer
131 * NSSATAV_CreateFromBER
133 * This routine creates an NSSATAV by decoding a BER- or DER-encoded
134 * ATAV. If the optional arena argument is non-null, the memory used
135 * will be obtained from that arena; otherwise, the memory will be
136 * obtained from the heap. This routine may return NULL upon error,
137 * in which case it will have created an error stack.
139 * The error may be one of the following values:
140 * NSS_ERROR_INVALID_BER
141 * NSS_ERROR_NO_MEMORY
143 * Return value:
144 * NULL upon error
145 * A pointer to an NSSATAV upon success
148 NSS_IMPLEMENT NSSATAV *
149 NSSATAV_CreateFromBER
151 NSSArena *arenaOpt,
152 NSSBER *berATAV
155 nss_ClearErrorStack();
157 #ifdef DEBUG
158 if( (NSSArena *)NULL != arenaOpt ) {
159 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
160 return (NSSATAV *)NULL;
165 * NSSBERs can be created by the user,
166 * so no pointer-tracking can be checked.
169 if( (NSSBER *)NULL == berATAV ) {
170 nss_SetError(NSS_ERROR_INVALID_BER);
171 return (NSSATAV *)NULL;
174 if( (void *)NULL == berATAV->data ) {
175 nss_SetError(NSS_ERROR_INVALID_BER);
176 return (NSSATAV *)NULL;
178 #endif /* DEBUG */
180 return nssATAV_CreateFromBER(arenaOpt, berATAV);
184 * NSSATAV_CreateFromUTF8
186 * This routine creates an NSSATAV by decoding a UTF8 string in the
187 * "equals" format, e.g., "c=US." If the optional arena argument is
188 * non-null, the memory used will be obtained from that arena;
189 * otherwise, the memory will be obtained from the heap. This routine
190 * may return NULL upon error, in which case it will have created an
191 * error stack.
193 * The error may be one of the following values:
194 * NSS_ERROR_UNKNOWN_ATTRIBUTE
195 * NSS_ERROR_INVALID_STRING
196 * NSS_ERROR_NO_MEMORY
198 * Return value:
199 * NULL upon error
200 * A pointer to an NSSATAV upon success
203 NSS_IMPLEMENT NSSATAV *
204 NSSATAV_CreateFromUTF8
206 NSSArena *arenaOpt,
207 NSSUTF8 *stringATAV
210 nss_ClearErrorStack();
212 #ifdef DEBUG
213 if( (NSSArena *)NULL != arenaOpt ) {
214 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
215 return (NSSATAV *)NULL;
220 * NSSUTF8s can be created by the user,
221 * so no pointer-tracking can be checked.
224 if( (NSSUTF8 *)NULL == stringATAV ) {
225 nss_SetError(NSS_ERROR_INVALID_UTF8);
226 return (NSSATAV *)NULL;
228 #endif /* DEBUG */
230 return nssATAV_CreateFromUTF8(arenaOpt, stringATAV);
234 * NSSATAV_Create
236 * This routine creates an NSSATAV from the specified NSSOID and the
237 * specified data. If the optional arena argument is non-null, the
238 * memory used will be obtained from that arena; otherwise, the memory
239 * will be obtained from the heap.If the specified data length is zero,
240 * the data is assumed to be terminated by first zero byte; this allows
241 * UTF8 strings to be easily specified. This routine may return NULL
242 * upon error, in which case it will have created an error stack.
244 * The error may be one of the following values:
245 * NSS_ERROR_INVALID_ARENA
246 * NSS_ERROR_INVALID_NSSOID
247 * NSS_ERROR_INVALID_POINTER
248 * NSS_ERROR_NO_MEMORY
250 * Return value:
251 * NULL upon error
252 * A pointer to an NSSATAV upon success
255 NSS_IMPLEMENT NSSATAV *
256 NSSATAV_Create
258 NSSArena *arenaOpt,
259 const NSSOID *oid,
260 const void *data,
261 PRUint32 length
264 nss_ClearErrorStack();
266 #ifdef DEBUG
267 if( (NSSArena *)NULL != arenaOpt ) {
268 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
269 return (NSSATAV *)NULL;
273 if( PR_SUCCESS != nssOID_verifyPointer(oid) ) {
274 return (NSSATAV *)NULL;
277 if( (const void *)NULL == data ) {
278 nss_SetError(NSS_ERROR_INVALID_POINTER);
279 return (NSSATAV *)NULL;
281 #endif /* DEBUG */
283 return nssATAV_Create(arenaOpt, oid, data, length);
287 * NSSATAV_Destroy
289 * This routine will destroy an ATAV object. It should eventually be
290 * called on all ATAVs created without an arena. While it is not
291 * necessary to call it on ATAVs created within an arena, it is not an
292 * error to do so. This routine returns a PRStatus value; if
293 * successful, it will return PR_SUCCESS. If unsuccessful, it will
294 * create an error stack and return PR_FAILURE.
296 * The error may be one of the following values:
297 * NSS_ERROR_INVALID_ATAV
299 * Return value:
300 * PR_FAILURE upon error
301 * PR_SUCCESS upon success
304 NSS_IMPLEMENT PRStatus
305 NSSATAV_Destroy
307 NSSATAV *atav
310 nss_ClearErrorStack();
312 #ifdef DEBUG
313 if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
314 return PR_FAILURE;
316 #endif /* DEBUG */
318 return nssATAV_Destroy(atav);
322 * NSSATAV_GetDEREncoding
324 * This routine will DER-encode an ATAV object. If the optional arena
325 * argument is non-null, the memory used will be obtained from that
326 * arena; otherwise, the memory will be obtained from the heap. This
327 * routine may return null upon error, in which case it will have
328 * created an error stack.
330 * The error may be one of the following values:
331 * NSS_ERROR_INVALID_ATAV
332 * NSS_ERROR_NO_MEMORY
334 * Return value:
335 * NULL upon error
336 * The DER encoding of this NSSATAV
339 NSS_IMPLEMENT NSSDER *
340 NSSATAV_GetDEREncoding
342 NSSATAV *atav,
343 NSSArena *arenaOpt
346 nss_ClearErrorStack();
348 #ifdef DEBUG
349 if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
350 return (NSSDER *)NULL;
353 if( (NSSArena *)NULL != arenaOpt ) {
354 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
355 return (NSSDER *)NULL;
358 #endif /* DEBUG */
360 return nssATAV_GetDEREncoding(atav, arenaOpt);
364 * NSSATAV_GetUTF8Encoding
366 * This routine returns a UTF8 string containing a string
367 * representation of the ATAV in "equals" notation (e.g., "o=Acme").
368 * If the optional arena argument is non-null, the memory used will be
369 * obtained from that arena; otherwise, the memory will be obtained
370 * from the heap. This routine may return null upon error, in which
371 * case it will have created an error stack.
373 * The error may be one of the following values:
374 * NSS_ERROR_INVALID_ATAV
375 * NSS_ERROR_NO_MEMORY
377 * Return value:
378 * NULL upon error
379 * A pointer to a UTF8 string containing the "equals" encoding of the
380 * ATAV
383 NSS_IMPLEMENT NSSUTF8 *
384 NSSATAV_GetUTF8Encoding
386 NSSATAV *atav,
387 NSSArena *arenaOpt
390 nss_ClearErrorStack();
392 #ifdef DEBUG
393 if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
394 return (NSSUTF8 *)NULL;
397 if( (NSSArena *)NULL != arenaOpt ) {
398 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
399 return (NSSUTF8 *)NULL;
402 #endif /* DEBUG */
404 return nssATAV_GetUTF8Encoding(atav, arenaOpt);
408 * NSSATAV_GetType
410 * This routine returns the NSSOID corresponding to the attribute type
411 * in the specified ATAV. This routine may return NSS_OID_UNKNOWN
412 * upon error, in which case it will have created an error stack.
414 * The error may be one of the following values:
415 * NSS_ERROR_INVALID_ATAV
417 * Return value:
418 * NSS_OID_UNKNOWN upon error
419 * An element of enum NSSOIDenum upon success
422 NSS_IMPLEMENT const NSSOID *
423 NSSATAV_GetType
425 NSSATAV *atav
428 nss_ClearErrorStack();
430 #ifdef DEBUG
431 if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
432 return (NSSOID *)NULL;
434 #endif /* DEBUG */
436 return nssATAV_GetType(atav);
440 * NSSATAV_GetValue
442 * This routine returns a string containing the attribute value
443 * in the specified ATAV. If the optional arena argument is non-null,
444 * the memory used will be obtained from that arena; otherwise, the
445 * memory will be obtained from the heap. This routine may return
446 * NULL upon error, in which case it will have created an error stack.
448 * The error may be one of the following values:
449 * NSS_ERROR_INVALID_ATAV
450 * NSS_ERROR_NO_MEMORY
452 * Return value:
453 * NULL upon error
454 * A pointer to an NSSItem containing the attribute value.
457 NSS_IMPLEMENT NSSUTF8 *
458 NSSATAV_GetValue
460 NSSATAV *atav,
461 NSSArena *arenaOpt
464 nss_ClearErrorStack();
466 #ifdef DEBUG
467 if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
468 return (NSSUTF8 *)NULL;
471 if( (NSSArena *)NULL != arenaOpt ) {
472 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
473 return (NSSUTF8 *)NULL;
476 #endif /* DEBUG */
478 return nssATAV_GetValue(atav, arenaOpt);
482 * NSSATAV_Compare
484 * This routine compares two ATAVs for equality. For two ATAVs to be
485 * equal, the attribute types must be the same, and the attribute
486 * values must have equal length and contents. The result of the
487 * comparison will be stored at the location pointed to by the "equalp"
488 * variable, which must point to a valid PRBool. This routine may
489 * return PR_FAILURE upon error, in which case it will have created an
490 * error stack.
492 * The error may be one of the following values:
493 * NSS_ERROR_INVALID_ATAV
494 * NSS_ERROR_INVALID_ARGUMENT
496 * Return value:
497 * PR_FAILURE on error
498 * PR_SUCCESS upon a successful comparison (equal or not)
501 NSS_IMPLEMENT PRStatus
502 NSSATAV_Compare
504 NSSATAV *atav1,
505 NSSATAV *atav2,
506 PRBool *equalp
509 nss_ClearErrorStack();
511 #ifdef DEBUG
512 if( PR_SUCCESS != nssATAV_verifyPointer(atav1) ) {
513 return PR_FAILURE;
516 if( PR_SUCCESS != nssATAV_verifyPointer(atav2) ) {
517 return PR_FAILURE;
520 if( (PRBool *)NULL == equalp ) {
521 nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
522 return PR_FAILURE;
524 #endif /* DEBUG */
526 return nssATAV_Compare(atav1, atav2, equalp);
530 * NSSATAV_Duplicate
532 * This routine duplicates the specified ATAV. If the optional arena
533 * argument is non-null, the memory required will be obtained from
534 * that arena; otherwise, the memory will be obtained from the heap.
535 * This routine may return NULL upon error, in which case it will have
536 * created an error stack.
538 * The error may be one of the following values:
539 * NSS_ERROR_INVALID_ATAV
540 * NSS_ERROR_NO_MEMORY
542 * Return value:
543 * NULL on error
544 * A pointer to a new ATAV
547 NSS_IMPLEMENT NSSATAV *
548 NSSATAV_Duplicate
550 NSSATAV *atav,
551 NSSArena *arenaOpt
554 nss_ClearErrorStack();
556 #ifdef DEBUG
557 if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
558 return (NSSATAV *)NULL;
561 if( (NSSArena *)NULL != arenaOpt ) {
562 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
563 return (NSSATAV *)NULL;
566 #endif /* DEBUG */
568 return nssATAV_Duplicate(atav, arenaOpt);
572 * The pointer-tracking code
575 #ifdef DEBUG
576 extern const NSSError NSS_ERROR_INTERNAL_ERROR;
578 static nssPointerTracker atav_pointer_tracker;
580 static PRStatus
581 atav_add_pointer
583 const NSSATAV *atav
586 PRStatus rv;
588 rv = nssPointerTracker_initialize(&atav_pointer_tracker);
589 if( PR_SUCCESS != rv ) {
590 return rv;
593 rv = nssPointerTracker_add(&atav_pointer_tracker, atav);
594 if( PR_SUCCESS != rv ) {
595 NSSError e = NSS_GetError();
596 if( NSS_ERROR_NO_MEMORY != e ) {
597 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
600 return rv;
603 return PR_SUCCESS;
606 static PRStatus
607 atav_remove_pointer
609 const NSSATAV *atav
612 PRStatus rv;
614 rv = nssPointerTracker_remove(&atav_pointer_tracker, atav);
615 if( PR_SUCCESS != rv ) {
616 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
619 return rv;
623 * nssATAV_verifyPointer
625 * This method is only present in debug builds.
627 * If the specified pointer is a valid pointer to an NSSATAV object,
628 * this routine will return PR_SUCCESS. Otherwise, it will put an
629 * error on the error stack and return PR_FAILRUE.
631 * The error may be one of the following values:
632 * NSS_ERROR_INVALID_NSSATAV
633 * NSS_ERROR_NO_MEMORY
635 * Return value:
636 * PR_SUCCESS if the pointer is valid
637 * PR_FAILURE if it isn't
640 NSS_IMPLEMENT PRStatus
641 nssATAV_verifyPointer
643 NSSATAV *atav
646 PRStatus rv;
648 rv = nssPointerTracker_initialize(&atav_pointer_tracker);
649 if( PR_SUCCESS != rv ) {
650 return PR_FAILURE;
653 rv = nssPointerTracker_verify(&atav_pointer_tracker, atav);
654 if( PR_SUCCESS != rv ) {
655 nss_SetError(NSS_ERROR_INVALID_ATAV);
656 return PR_FAILURE;
659 return PR_SUCCESS;
661 #endif /* DEBUG */
663 typedef struct {
664 NSSBER oid;
665 NSSBER value;
666 } atav_holder;
668 static const nssASN1Template nss_atav_template[] = {
669 { nssASN1_SEQUENCE, 0, NULL, sizeof(atav_holder) },
670 { nssASN1_OBJECT_ID, nsslibc_offsetof(atav_holder, oid), NULL, 0 },
671 { nssASN1_ANY, nsslibc_offsetof(atav_holder, value), NULL, 0 },
672 { 0, 0, NULL, 0 }
676 * There are several common attributes, with well-known type aliases
677 * and value semantics. This table lists the ones we recognize.
680 struct nss_attribute_data_str {
681 const NSSOID **oid;
682 nssStringType stringType;
683 PRUint32 minStringLength;
684 PRUint32 maxStringLength; /* zero for no limit */
687 static const struct nss_attribute_data_str nss_attribute_data[] = {
688 { &NSS_OID_X520_NAME,
689 nssStringType_DirectoryString, 1, 32768 },
690 { &NSS_OID_X520_COMMON_NAME,
691 nssStringType_DirectoryString, 1, 64 },
692 { &NSS_OID_X520_SURNAME,
693 nssStringType_DirectoryString, 1, 40 },
694 { &NSS_OID_X520_GIVEN_NAME,
695 nssStringType_DirectoryString, 1, 16 },
696 { &NSS_OID_X520_INITIALS,
697 nssStringType_DirectoryString, 1, 5 },
698 { &NSS_OID_X520_GENERATION_QUALIFIER,
699 nssStringType_DirectoryString, 1, 3 },
700 { &NSS_OID_X520_DN_QUALIFIER,
701 nssStringType_PrintableString, 1, 0 },
702 { &NSS_OID_X520_COUNTRY_NAME,
703 nssStringType_PrintableString, 2, 2 },
704 { &NSS_OID_X520_LOCALITY_NAME,
705 nssStringType_DirectoryString, 1, 128 },
706 { &NSS_OID_X520_STATE_OR_PROVINCE_NAME,
707 nssStringType_DirectoryString, 1, 128 },
708 { &NSS_OID_X520_ORGANIZATION_NAME,
709 nssStringType_DirectoryString, 1, 64 },
710 { &NSS_OID_X520_ORGANIZATIONAL_UNIT_NAME,
711 nssStringType_DirectoryString, 1,
713 * Note, draft #11 defines both "32" and "64" for this maximum,
714 * in two separate places. Until it's settled, "conservative
715 * in what you send." We're always liberal in what we accept.
717 32 },
718 { &NSS_OID_X520_TITLE,
719 nssStringType_DirectoryString, 1, 64 },
720 { &NSS_OID_RFC1274_EMAIL,
721 nssStringType_PHGString, 1, 128 }
724 PRUint32 nss_attribute_data_quantity =
725 (sizeof(nss_attribute_data)/sizeof(nss_attribute_data[0]));
727 static nssStringType
728 nss_attr_underlying_string_form
730 nssStringType type,
731 void *data
734 if( nssStringType_DirectoryString == type ) {
735 PRUint8 tag = *(PRUint8 *)data;
736 switch( tag & nssASN1_TAGNUM_MASK ) {
737 case 20:
739 * XXX fgmr-- we have to accept Latin-1 for Teletex; (see
740 * below) but is T61 a suitable value for "Latin-1"?
742 return nssStringType_TeletexString;
743 case 19:
744 return nssStringType_PrintableString;
745 case 28:
746 return nssStringType_UniversalString;
747 case 30:
748 return nssStringType_BMPString;
749 case 12:
750 return nssStringType_UTF8String;
751 default:
752 return nssStringType_Unknown;
756 return type;
761 * This routine decodes the attribute value, in a type-specific way.
765 static NSSUTF8 *
766 nss_attr_to_utf8
768 NSSArena *arenaOpt,
769 const NSSOID *oid,
770 NSSItem *item,
771 nssStringType *stringForm
774 NSSUTF8 *rv = (NSSUTF8 *)NULL;
775 PRUint32 i;
776 const struct nss_attribute_data_str *which =
777 (struct nss_attribute_data_str *)NULL;
778 PRUint32 len = 0;
780 for( i = 0; i < nss_attribute_data_quantity; i++ ) {
781 if( *(nss_attribute_data[ i ].oid) == oid ) {
782 which = &nss_attribute_data[i];
783 break;
787 if( (struct nss_attribute_data_str *)NULL == which ) {
788 /* Unknown OID. Encode it as hex. */
789 PRUint8 *c;
790 PRUint8 *d = (PRUint8 *)item->data;
791 PRUint32 amt = item->size;
793 if( item->size >= 0x7FFFFFFF ) {
794 nss_SetError(NSS_ERROR_INVALID_STRING);
795 return (NSSUTF8 *)NULL;
798 len = 1 + (item->size * 2) + 1; /* '#' + hex + '\0' */
799 rv = (NSSUTF8 *)nss_ZAlloc(arenaOpt, len);
800 if( (NSSUTF8 *)NULL == rv ) {
801 return (NSSUTF8 *)NULL;
804 c = (PRUint8 *)rv;
805 *c++ = '#'; /* XXX fgmr check this */
806 while( amt > 0 ) {
807 static char hex[16] = "0123456789ABCDEF";
808 *c++ = hex[ ((*d) & 0xf0) >> 4 ];
809 *c++ = hex[ ((*d) & 0x0f) ];
812 /* *c = '\0'; nss_ZAlloc, remember */
814 *stringForm = nssStringType_Unknown; /* force exact comparison */
815 } else {
816 PRStatus status;
817 rv = nssUTF8_CreateFromBER(arenaOpt, which->stringType,
818 (NSSBER *)item);
820 if( (NSSUTF8 *)NULL == rv ) {
821 return (NSSUTF8 *)NULL;
824 len = nssUTF8_Length(rv, &status);
825 if( PR_SUCCESS != status || len == 0 ) {
826 nss_ZFreeIf(rv);
827 return (NSSUTF8 *)NULL;
830 *stringForm = nss_attr_underlying_string_form(which->stringType,
831 item->data);
834 return rv;
838 * nssATAV_CreateFromBER
840 * This routine creates an NSSATAV by decoding a BER- or DER-encoded
841 * ATAV. If the optional arena argument is non-null, the memory used
842 * will be obtained from that arena; otherwise, the memory will be
843 * obtained from the heap. This routine may return NULL upon error,
844 * in which case it will have set an error on the error stack.
846 * The error may be one of the following values:
847 * NSS_ERROR_INVALID_BER
848 * NSS_ERROR_NO_MEMORY
850 * Return value:
851 * NULL upon error
852 * A pointer to an NSSATAV upon success
855 NSS_IMPLEMENT NSSATAV *
856 nssATAV_CreateFromBER
858 NSSArena *arenaOpt,
859 const NSSBER *berATAV
862 atav_holder holder;
863 PRStatus status;
864 NSSATAV *rv;
866 #ifdef NSSDEBUG
867 if( (NSSArena *)NULL != arenaOpt ) {
868 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
869 return (NSSATAV *)NULL;
874 * NSSBERs can be created by the user,
875 * so no pointer-tracking can be checked.
878 if( (NSSBER *)NULL == berATAV ) {
879 nss_SetError(NSS_ERROR_INVALID_BER);
880 return (NSSATAV *)NULL;
883 if( (void *)NULL == berATAV->data ) {
884 nss_SetError(NSS_ERROR_INVALID_BER);
885 return (NSSATAV *)NULL;
887 #endif /* NSSDEBUG */
889 status = nssASN1_DecodeBER(arenaOpt, &holder,
890 nss_atav_template, berATAV);
891 if( PR_SUCCESS != status ) {
892 return (NSSATAV *)NULL;
895 rv = nss_ZNEW(arenaOpt, NSSATAV);
896 if( (NSSATAV *)NULL == rv ) {
897 nss_ZFreeIf(holder.oid.data);
898 nss_ZFreeIf(holder.value.data);
899 return (NSSATAV *)NULL;
902 rv->oid = nssOID_CreateFromBER(&holder.oid);
903 if( (NSSOID *)NULL == rv->oid ) {
904 nss_ZFreeIf(rv);
905 nss_ZFreeIf(holder.oid.data);
906 nss_ZFreeIf(holder.value.data);
907 return (NSSATAV *)NULL;
910 nss_ZFreeIf(holder.oid.data);
912 rv->ber.data = nss_ZAlloc(arenaOpt, berATAV->size);
913 if( (void *)NULL == rv->ber.data ) {
914 nss_ZFreeIf(rv);
915 nss_ZFreeIf(holder.value.data);
916 return (NSSATAV *)NULL;
919 rv->ber.size = berATAV->size;
920 (void)nsslibc_memcpy(rv->ber.data, berATAV->data, berATAV->size);
922 rv->value = nss_attr_to_utf8(arenaOpt, rv->oid, &holder.value,
923 &rv->stringForm);
924 if( (NSSUTF8 *)NULL == rv->value ) {
925 nss_ZFreeIf(rv->ber.data);
926 nss_ZFreeIf(rv);
927 nss_ZFreeIf(holder.value.data);
928 return (NSSATAV *)NULL;
931 nss_ZFreeIf(holder.value.data);
933 #ifdef DEBUG
934 if( PR_SUCCESS != atav_add_pointer(rv) ) {
935 nss_ZFreeIf(rv->ber.data);
936 nss_ZFreeIf(rv->value);
937 nss_ZFreeIf(rv);
938 return (NSSATAV *)NULL;
940 #endif /* DEBUG */
942 return rv;
945 static PRBool
946 nss_atav_utf8_string_is_hex
948 const NSSUTF8 *s
951 /* All hex digits are ASCII, so this works */
952 PRUint8 *p = (PRUint8 *)s;
954 for( ; (PRUint8)0 != *p; p++ ) {
955 if( (('0' <= *p) && (*p <= '9')) ||
956 (('A' <= *p) && (*p <= 'F')) ||
957 (('a' <= *p) && (*p <= 'f')) ) {
958 continue;
959 } else {
960 return PR_FALSE;
964 return PR_TRUE;
967 static NSSUTF8
968 nss_atav_fromhex
970 NSSUTF8 *d
973 NSSUTF8 rv;
975 if( d[0] <= '9' ) {
976 rv = (d[0] - '0') * 16;
977 } else if( d[0] >= 'a' ) {
978 rv = (d[0] - 'a' + 10) * 16;
979 } else {
980 rv = (d[0] - 'A' + 10);
983 if( d[1] <= '9' ) {
984 rv += (d[1] - '0');
985 } else if( d[1] >= 'a' ) {
986 rv += (d[1] - 'a' + 10);
987 } else {
988 rv += (d[1] - 'A' + 10);
991 return rv;
995 * nssATAV_CreateFromUTF8
997 * This routine creates an NSSATAV by decoding a UTF8 string in the
998 * "equals" format, e.g., "c=US." If the optional arena argument is
999 * non-null, the memory used will be obtained from that arena;
1000 * otherwise, the memory will be obtained from the heap. This routine
1001 * may return NULL upon error, in which case it will have set an error
1002 * on the error stack.
1004 * The error may be one of the following values:
1005 * NSS_ERROR_UNKNOWN_ATTRIBUTE
1006 * NSS_ERROR_INVALID_STRING
1007 * NSS_ERROR_NO_MEMORY
1009 * Return value:
1010 * NULL upon error
1011 * A pointer to an NSSATAV upon success
1014 extern const NSSError NSS_ERROR_INTERNAL_ERROR;
1016 NSS_IMPLEMENT NSSATAV *
1017 nssATAV_CreateFromUTF8
1019 NSSArena *arenaOpt,
1020 const NSSUTF8 *stringATAV
1023 char *c;
1024 NSSUTF8 *type;
1025 NSSUTF8 *value;
1026 PRUint32 i;
1027 const NSSOID *oid = (NSSOID *)NULL;
1028 NSSATAV *rv;
1029 NSSItem xitem;
1031 xitem.data = (void *)NULL;
1033 for( c = (char *)stringATAV; '\0' != *c; c++ ) {
1034 if( '=' == *c ) {
1035 #ifdef PEDANTIC
1037 * Theoretically, one could have an '=' in an
1038 * attribute string alias. We don't, yet, though.
1040 if( (char *)stringATAV == c ) {
1041 nss_SetError(NSS_ERROR_INVALID_STRING);
1042 return (NSSATAV *)NULL;
1043 } else {
1044 if( '\\' == c[-1] ) {
1045 continue;
1048 #endif /* PEDANTIC */
1049 break;
1053 if( '\0' == *c ) {
1054 nss_SetError(NSS_ERROR_INVALID_UTF8);
1055 return (NSSATAV *)NULL;
1056 } else {
1057 c++;
1058 value = (NSSUTF8 *)c;
1061 i = ((NSSUTF8 *)c - stringATAV);
1062 type = (NSSUTF8 *)nss_ZAlloc((NSSArena *)NULL, i);
1063 if( (NSSUTF8 *)NULL == type ) {
1064 return (NSSATAV *)NULL;
1067 (void)nsslibc_memcpy(type, stringATAV, i-1);
1069 c = (char *)stringATAV;
1070 if( (('0' <= *c) && (*c <= '9')) || ('#' == *c) ) {
1071 oid = nssOID_CreateFromUTF8(type);
1072 if( (NSSOID *)NULL == oid ) {
1073 nss_ZFreeIf(type);
1074 return (NSSATAV *)NULL;
1076 } else {
1077 for( i = 0; i < nss_attribute_type_alias_count; i++ ) {
1078 PRStatus status;
1079 const nssAttributeTypeAliasTable *e = &nss_attribute_type_aliases[i];
1080 PRBool match = nssUTF8_CaseIgnoreMatch(type, e->alias, &status);
1081 if( PR_SUCCESS != status ) {
1082 nss_ZFreeIf(type);
1083 return (NSSATAV *)NULL;
1085 if( PR_TRUE == match ) {
1086 oid = *(e->oid);
1087 break;
1091 if( (NSSOID *)NULL == oid ) {
1092 nss_ZFreeIf(type);
1093 nss_SetError(NSS_ERROR_UNKNOWN_ATTRIBUTE);
1094 return (NSSATAV *)NULL;
1098 nss_ZFreeIf(type);
1099 type = (NSSUTF8 *)NULL;
1101 rv = nss_ZNEW(arenaOpt, NSSATAV);
1102 if( (NSSATAV *)NULL == rv ) {
1103 return (NSSATAV *)NULL;
1106 rv->oid = oid;
1108 if( '#' == *value ) { /* XXX fgmr.. was it '#'? or backslash? */
1109 PRUint32 size;
1110 PRUint32 len;
1111 NSSUTF8 *c;
1112 NSSUTF8 *d;
1113 PRStatus status;
1114 /* It's in hex */
1116 value++;
1117 if( PR_TRUE != nss_atav_utf8_string_is_hex(value) ) {
1118 (void)nss_ZFreeIf(rv);
1119 nss_SetError(NSS_ERROR_INVALID_STRING);
1120 return (NSSATAV *)NULL;
1123 size = nssUTF8_Size(value, &status);
1124 if( PR_SUCCESS != status ) {
1126 * Only returns an error on bad pointer (nope) or string
1127 * too long. The defined limits for known attributes are
1128 * small enough to fit in PRUint32, and when undefined we
1129 * get to apply our own practical limits. Ergo, I say the
1130 * string is invalid.
1132 (void)nss_ZFreeIf(rv);
1133 nss_SetError(NSS_ERROR_INVALID_STRING);
1134 return (NSSATAV *)NULL;
1137 if( ((size-1) & 1) ) {
1138 /* odd length */
1139 (void)nss_ZFreeIf(rv);
1140 nss_SetError(NSS_ERROR_INVALID_STRING);
1141 return (NSSATAV *)NULL;
1144 len = (size-1)/2;
1146 rv->value = (NSSUTF8 *)nss_ZAlloc(arenaOpt, len+1);
1147 if( (NSSUTF8 *)NULL == rv->value ) {
1148 (void)nss_ZFreeIf(rv);
1149 return (NSSATAV *)NULL;
1152 xitem.size = len;
1153 xitem.data = (void *)rv->value;
1155 for( c = rv->value, d = value; len--; c++, d += 2 ) {
1156 *c = nss_atav_fromhex(d);
1159 *c = 0;
1160 } else {
1161 PRStatus status;
1162 PRUint32 i, len;
1163 PRUint8 *s;
1166 * XXX fgmr-- okay, this is a little wasteful, and should
1167 * probably be abstracted out a bit. Later.
1170 rv->value = nssUTF8_Duplicate(value, arenaOpt);
1171 if( (NSSUTF8 *)NULL == rv->value ) {
1172 (void)nss_ZFreeIf(rv);
1173 return (NSSATAV *)NULL;
1176 len = nssUTF8_Size(rv->value, &status);
1177 if( PR_SUCCESS != status ) {
1178 (void)nss_ZFreeIf(rv->value);
1179 (void)nss_ZFreeIf(rv);
1180 return (NSSATAV *)NULL;
1183 s = (PRUint8 *)rv->value;
1184 for( i = 0; i < len; i++ ) {
1185 if( '\\' == s[i] ) {
1186 (void)nsslibc_memcpy(&s[i], &s[i+1], len-i-1);
1191 /* Now just BER-encode the baby and we're through.. */
1193 const struct nss_attribute_data_str *which =
1194 (struct nss_attribute_data_str *)NULL;
1195 PRUint32 i;
1196 NSSArena *a;
1197 NSSDER *oidder;
1198 NSSItem *vitem;
1199 atav_holder ah;
1200 NSSDER *status;
1202 for( i = 0; i < nss_attribute_data_quantity; i++ ) {
1203 if( *(nss_attribute_data[ i ].oid) == rv->oid ) {
1204 which = &nss_attribute_data[i];
1205 break;
1209 a = NSSArena_Create();
1210 if( (NSSArena *)NULL == a ) {
1211 (void)nss_ZFreeIf(rv->value);
1212 (void)nss_ZFreeIf(rv);
1213 return (NSSATAV *)NULL;
1216 oidder = nssOID_GetDEREncoding(rv->oid, (NSSDER *)NULL, a);
1217 if( (NSSDER *)NULL == oidder ) {
1218 (void)NSSArena_Destroy(a);
1219 (void)nss_ZFreeIf(rv->value);
1220 (void)nss_ZFreeIf(rv);
1221 return (NSSATAV *)NULL;
1224 if( (struct nss_attribute_data_str *)NULL == which ) {
1226 * We'll just have to take the user data as an octet stream.
1228 if( (void *)NULL == xitem.data ) {
1230 * This means that an ATTR entry has been added to oids.txt,
1231 * but no corresponding entry has been added to the array
1232 * ns_attribute_data[] above.
1234 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
1235 (void)NSSArena_Destroy(a);
1236 (void)nss_ZFreeIf(rv->value);
1237 (void)nss_ZFreeIf(rv);
1238 return (NSSATAV *)NULL;
1241 vitem = nssASN1_EncodeItem(a, (NSSDER *)NULL, &xitem,
1242 nssASN1Template_OctetString, NSSASN1DER);
1243 if( (NSSItem *)NULL == vitem ) {
1244 (void)NSSArena_Destroy(a);
1245 (void)nss_ZFreeIf(rv->value);
1246 (void)nss_ZFreeIf(rv);
1247 return (NSSATAV *)NULL;
1250 rv->stringForm = nssStringType_Unknown;
1251 } else {
1252 PRUint32 length = 0;
1253 PRStatus stat;
1255 length = nssUTF8_Length(rv->value, &stat);
1256 if( PR_SUCCESS != stat ) {
1257 (void)NSSArena_Destroy(a);
1258 (void)nss_ZFreeIf(rv->value);
1259 (void)nss_ZFreeIf(rv);
1260 return (NSSATAV *)NULL;
1263 if( ((0 != which->minStringLength) &&
1264 (length < which->minStringLength)) ||
1265 ((0 != which->maxStringLength) &&
1266 (length > which->maxStringLength)) ) {
1267 nss_SetError(NSS_ERROR_INVALID_STRING);
1268 (void)NSSArena_Destroy(a);
1269 (void)nss_ZFreeIf(rv->value);
1270 (void)nss_ZFreeIf(rv);
1271 return (NSSATAV *)NULL;
1274 vitem = nssUTF8_GetDEREncoding(a, which->stringType, rv->value);
1275 if( (NSSItem *)NULL == vitem ) {
1276 (void)NSSArena_Destroy(a);
1277 (void)nss_ZFreeIf(rv->value);
1278 (void)nss_ZFreeIf(rv);
1279 return (NSSATAV *)NULL;
1282 if( nssStringType_DirectoryString == which->stringType ) {
1283 rv->stringForm = nssStringType_UTF8String;
1284 } else {
1285 rv->stringForm = which->stringType;
1289 ah.oid = *oidder;
1290 ah.value = *vitem;
1292 status = nssASN1_EncodeItem(arenaOpt, &rv->ber, &ah,
1293 nss_atav_template, NSSASN1DER);
1295 if( (NSSDER *)NULL == status ) {
1296 (void)NSSArena_Destroy(a);
1297 (void)nss_ZFreeIf(rv->value);
1298 (void)nss_ZFreeIf(rv);
1299 return (NSSATAV *)NULL;
1302 (void)NSSArena_Destroy(a);
1305 return rv;
1309 * nssATAV_Create
1311 * This routine creates an NSSATAV from the specified NSSOID and the
1312 * specified data. If the optional arena argument is non-null, the
1313 * memory used will be obtained from that arena; otherwise, the memory
1314 * will be obtained from the heap.If the specified data length is zero,
1315 * the data is assumed to be terminated by first zero byte; this allows
1316 * UTF8 strings to be easily specified. This routine may return NULL
1317 * upon error, in which case it will have set an error on the error
1318 * stack.
1320 * The error may be one of the following values:
1321 * NSS_ERROR_INVALID_ARENA
1322 * NSS_ERROR_INVALID_NSSOID
1323 * NSS_ERROR_INVALID_POINTER
1324 * NSS_ERROR_NO_MEMORY
1326 * Return value:
1327 * NULL upon error
1328 * A pointer to an NSSATAV upon success
1331 NSS_IMPLEMENT NSSATAV *
1332 nssATAV_Create
1334 NSSArena *arenaOpt,
1335 const NSSOID *oid,
1336 const void *data,
1337 PRUint32 length
1340 #ifdef NSSDEBUG
1341 if( (NSSArena *)NULL != arenaOpt ) {
1342 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
1343 return (NSSATAV *)NULL;
1347 if( PR_SUCCESS != nssOID_verifyPointer(oid) ) {
1348 return (NSSATAV *)NULL;
1351 if( (const void *)NULL == data ) {
1352 nss_SetError(NSS_ERROR_INVALID_POINTER);
1353 return (NSSATAV *)NULL;
1355 #endif /* NSSDEBUG */
1357 /* XXX fgmr-- oops, forgot this one */
1358 return (NSSATAV *)NULL;
1362 * nssATAV_Destroy
1364 * This routine will destroy an ATAV object. It should eventually be
1365 * called on all ATAVs created without an arena. While it is not
1366 * necessary to call it on ATAVs created within an arena, it is not an
1367 * error to do so. This routine returns a PRStatus value; if
1368 * successful, it will return PR_SUCCESS. If unsuccessful, it will
1369 * set an error on the error stack and return PR_FAILURE.
1371 * The error may be one of the following values:
1372 * NSS_ERROR_INVALID_ATAV
1374 * Return value:
1375 * PR_FAILURE upon error
1376 * PR_SUCCESS upon success
1379 NSS_IMPLEMENT PRStatus
1380 nssATAV_Destroy
1382 NSSATAV *atav
1385 #ifdef NSSDEBUG
1386 if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
1387 return PR_FAILURE;
1389 #endif /* NSSDEBUG */
1391 (void)nss_ZFreeIf(atav->ber.data);
1392 (void)nss_ZFreeIf(atav->value);
1394 #ifdef DEBUG
1395 if( PR_SUCCESS != atav_remove_pointer(atav) ) {
1396 return PR_FAILURE;
1398 #endif /* DEBUG */
1400 return PR_SUCCESS;
1404 * nssATAV_GetDEREncoding
1406 * This routine will DER-encode an ATAV object. If the optional arena
1407 * argument is non-null, the memory used will be obtained from that
1408 * arena; otherwise, the memory will be obtained from the heap. This
1409 * routine may return null upon error, in which case it will have set
1410 * an error on the error stack.
1412 * The error may be one of the following values:
1413 * NSS_ERROR_INVALID_ATAV
1414 * NSS_ERROR_NO_MEMORY
1416 * Return value:
1417 * NULL upon error
1418 * The DER encoding of this NSSATAV
1421 NSS_IMPLEMENT NSSDER *
1422 nssATAV_GetDEREncoding
1424 NSSATAV *atav,
1425 NSSArena *arenaOpt
1428 NSSDER *rv;
1430 #ifdef NSSDEBUG
1431 if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
1432 return (NSSDER *)NULL;
1434 #endif /* NSSDEBUG */
1436 rv = nss_ZNEW(arenaOpt, NSSDER);
1437 if( (NSSDER *)NULL == rv ) {
1438 return (NSSDER *)NULL;
1441 rv->data = nss_ZAlloc(arenaOpt, atav->ber.size);
1442 if( (void *)NULL == rv->data ) {
1443 (void)nss_ZFreeIf(rv);
1444 return (NSSDER *)NULL;
1447 rv->size = atav->ber.size;
1448 if( NULL == nsslibc_memcpy(rv->data, atav->ber.data, rv->size) ) {
1449 (void)nss_ZFreeIf(rv->data);
1450 (void)nss_ZFreeIf(rv);
1451 return (NSSDER *)NULL;
1454 return rv;
1458 * nssATAV_GetUTF8Encoding
1460 * This routine returns a UTF8 string containing a string
1461 * representation of the ATAV in "equals" notation (e.g., "o=Acme").
1462 * If the optional arena argument is non-null, the memory used will be
1463 * obtained from that arena; otherwise, the memory will be obtained
1464 * from the heap. This routine may return null upon error, in which
1465 * case it will have set an error on the error stack.
1467 * The error may be one of the following values:
1468 * NSS_ERROR_INVALID_ATAV
1469 * NSS_ERROR_NO_MEMORY
1471 * Return value:
1472 * NULL upon error
1473 * A pointer to a UTF8 string containing the "equals" encoding of the
1474 * ATAV
1477 NSS_IMPLEMENT NSSUTF8 *
1478 nssATAV_GetUTF8Encoding
1480 NSSATAV *atav,
1481 NSSArena *arenaOpt
1484 NSSUTF8 *rv;
1485 PRUint32 i;
1486 const NSSUTF8 *alias = (NSSUTF8 *)NULL;
1487 NSSUTF8 *oid;
1488 NSSUTF8 *value;
1489 PRUint32 oidlen;
1490 PRUint32 valuelen;
1491 PRUint32 totallen;
1492 PRStatus status;
1494 #ifdef NSSDEBUG
1495 if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
1496 return (NSSUTF8 *)NULL;
1498 #endif /* NSSDEBUG */
1500 for( i = 0; i < nss_attribute_type_alias_count; i++ ) {
1501 if( *(nss_attribute_type_aliases[i].oid) == atav->oid ) {
1502 alias = nss_attribute_type_aliases[i].alias;
1503 break;
1507 if( (NSSUTF8 *)NULL == alias ) {
1508 oid = nssOID_GetUTF8Encoding(atav->oid, (NSSArena *)NULL);
1509 if( (NSSUTF8 *)NULL == oid ) {
1510 return (NSSUTF8 *)NULL;
1513 oidlen = nssUTF8_Size(oid, &status);
1514 if( PR_SUCCESS != status ) {
1515 (void)nss_ZFreeIf(oid);
1516 return (NSSUTF8 *)NULL;
1518 } else {
1519 oidlen = nssUTF8_Size(alias, &status);
1520 if( PR_SUCCESS != status ) {
1521 return (NSSUTF8 *)NULL;
1523 oid = (NSSUTF8 *)NULL;
1526 value = nssATAV_GetValue(atav, (NSSArena *)NULL);
1527 if( (NSSUTF8 *)NULL == value ) {
1528 (void)nss_ZFreeIf(oid);
1529 return (NSSUTF8 *)NULL;
1532 valuelen = nssUTF8_Size(value, &status);
1533 if( PR_SUCCESS != status ) {
1534 (void)nss_ZFreeIf(value);
1535 (void)nss_ZFreeIf(oid);
1536 return (NSSUTF8 *)NULL;
1539 totallen = oidlen + valuelen - 1 + 1;
1540 rv = (NSSUTF8 *)nss_ZAlloc(arenaOpt, totallen);
1541 if( (NSSUTF8 *)NULL == rv ) {
1542 (void)nss_ZFreeIf(value);
1543 (void)nss_ZFreeIf(oid);
1544 return (NSSUTF8 *)NULL;
1547 if( (NSSUTF8 *)NULL == alias ) {
1548 if( (void *)NULL == nsslibc_memcpy(rv, oid, oidlen-1) ) {
1549 (void)nss_ZFreeIf(rv);
1550 (void)nss_ZFreeIf(value);
1551 (void)nss_ZFreeIf(oid);
1552 return (NSSUTF8 *)NULL;
1554 } else {
1555 if( (void *)NULL == nsslibc_memcpy(rv, alias, oidlen-1) ) {
1556 (void)nss_ZFreeIf(rv);
1557 (void)nss_ZFreeIf(value);
1558 return (NSSUTF8 *)NULL;
1562 rv[ oidlen-1 ] = '=';
1564 if( (void *)NULL == nsslibc_memcpy(&rv[oidlen], value, valuelen) ) {
1565 (void)nss_ZFreeIf(rv);
1566 (void)nss_ZFreeIf(value);
1567 (void)nss_ZFreeIf(oid);
1568 return (NSSUTF8 *)NULL;
1571 return rv;
1575 * nssATAV_GetType
1577 * This routine returns the NSSOID corresponding to the attribute type
1578 * in the specified ATAV. This routine may return NSS_OID_UNKNOWN
1579 * upon error, in which case it will have set an error on the error
1580 * stack.
1582 * The error may be one of the following values:
1583 * NSS_ERROR_INVALID_ATAV
1585 * Return value:
1586 * NSS_OID_UNKNOWN upon error
1587 * A valid NSSOID pointer upon success
1590 NSS_IMPLEMENT const NSSOID *
1591 nssATAV_GetType
1593 NSSATAV *atav
1596 #ifdef NSSDEBUG
1597 if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
1598 return (NSSOID *)NULL;
1600 #endif /* NSSDEBUG */
1602 return atav->oid;
1606 * nssATAV_GetValue
1608 * This routine returns a NSSUTF8 string containing the attribute value
1609 * in the specified ATAV. If the optional arena argument is non-null,
1610 * the memory used will be obtained from that arena; otherwise, the
1611 * memory will be obtained from the heap. This routine may return
1612 * NULL upon error, in which case it will have set an error upon the
1613 * error stack.
1615 * The error may be one of the following values:
1616 * NSS_ERROR_INVALID_ATAV
1617 * NSS_ERROR_NO_MEMORY
1619 * Return value:
1620 * NULL upon error
1621 * A pointer to an NSSItem containing the attribute value.
1624 NSS_IMPLEMENT NSSUTF8 *
1625 nssATAV_GetValue
1627 NSSATAV *atav,
1628 NSSArena *arenaOpt
1631 #ifdef NSSDEBUG
1632 if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
1633 return (NSSUTF8 *)NULL;
1635 #endif /* NSSDEBUG */
1637 return nssUTF8_Duplicate(atav->value, arenaOpt);
1641 * nssATAV_Compare
1643 * This routine compares two ATAVs for equality. For two ATAVs to be
1644 * equal, the attribute types must be the same, and the attribute
1645 * values must have equal length and contents. The result of the
1646 * comparison will be stored at the location pointed to by the "equalp"
1647 * variable, which must point to a valid PRBool. This routine may
1648 * return PR_FAILURE upon error, in which case it will have set an
1649 * error on the error stack.
1651 * The error may be one of the following values:
1652 * NSS_ERROR_INVALID_ATAV
1653 * NSS_ERROR_INVALID_ARGUMENT
1655 * Return value:
1656 * PR_FAILURE on error
1657 * PR_SUCCESS upon a successful comparison (equal or not)
1660 NSS_IMPLEMENT PRStatus
1661 nssATAV_Compare
1663 NSSATAV *atav1,
1664 NSSATAV *atav2,
1665 PRBool *equalp
1668 nssStringType comparison;
1669 PRUint32 len1;
1670 PRUint32 len2;
1671 PRStatus status;
1673 #ifdef DEBUG
1674 if( PR_SUCCESS != nssATAV_verifyPointer(atav1) ) {
1675 return PR_FAILURE;
1678 if( PR_SUCCESS != nssATAV_verifyPointer(atav2) ) {
1679 return PR_FAILURE;
1682 if( (PRBool *)NULL == equalp ) {
1683 nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
1684 return PR_FAILURE;
1686 #endif /* DEBUG */
1688 if( atav1->oid != atav2->oid ) {
1689 *equalp = PR_FALSE;
1690 return PR_SUCCESS;
1693 if( atav1->stringForm != atav2->stringForm ) {
1694 if( (nssStringType_PrintableString == atav1->stringForm) ||
1695 (nssStringType_PrintableString == atav2->stringForm) ) {
1696 comparison = nssStringType_PrintableString;
1697 } else if( (nssStringType_PHGString == atav1->stringForm) ||
1698 (nssStringType_PHGString == atav2->stringForm) ) {
1699 comparison = nssStringType_PHGString;
1700 } else {
1701 comparison = atav1->stringForm;
1703 } else {
1704 comparison = atav1->stringForm;
1707 switch( comparison ) {
1708 case nssStringType_DirectoryString:
1709 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
1710 return PR_FAILURE;
1711 case nssStringType_TeletexString:
1712 break;
1713 case nssStringType_PrintableString:
1714 *equalp = nssUTF8_PrintableMatch(atav1->value, atav2->value, &status);
1715 return status;
1716 /* Case-insensitive, with whitespace reduction */
1717 break;
1718 case nssStringType_UniversalString:
1719 break;
1720 case nssStringType_BMPString:
1721 break;
1722 case nssStringType_GeneralString:
1723 /* what to do here? */
1724 break;
1725 case nssStringType_UTF8String:
1726 break;
1727 case nssStringType_PHGString:
1728 /* Case-insensitive (XXX fgmr, actually see draft-11 pg. 21) */
1729 *equalp = nssUTF8_CaseIgnoreMatch(atav1->value, atav2->value, &status);
1730 return status;
1731 case nssStringType_Unknown:
1732 break;
1735 len1 = nssUTF8_Size(atav1->value, &status);
1736 if( PR_SUCCESS != status ) {
1737 return PR_FAILURE;
1740 len2 = nssUTF8_Size(atav2->value, &status);
1741 if( PR_SUCCESS != status ) {
1742 return PR_FAILURE;
1745 if( len1 != len2 ) {
1746 *equalp = PR_FALSE;
1747 return PR_SUCCESS;
1750 *equalp = nsslibc_memequal(atav1->value, atav2->value, len1, &status);
1751 return status;
1756 * nssATAV_Duplicate
1758 * This routine duplicates the specified ATAV. If the optional arena
1759 * argument is non-null, the memory required will be obtained from
1760 * that arena; otherwise, the memory will be obtained from the heap.
1761 * This routine may return NULL upon error, in which case it will have
1762 * placed an error on the error stack.
1764 * The error may be one of the following values:
1765 * NSS_ERROR_INVALID_ATAV
1766 * NSS_ERROR_NO_MEMORY
1768 * Return value:
1769 * NULL on error
1770 * A pointer to a new ATAV
1773 NSS_IMPLEMENT NSSATAV *
1774 nssATAV_Duplicate
1776 NSSATAV *atav,
1777 NSSArena *arenaOpt
1780 NSSATAV *rv;
1782 #ifdef NSSDEBUG
1783 if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
1784 return (NSSATAV *)NULL;
1787 if( (NSSArena *)NULL != arenaOpt ) {
1788 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
1789 return (NSSATAV *)NULL;
1792 #endif /* NSSDEBUG */
1794 rv = nss_ZNEW(arenaOpt, NSSATAV);
1795 if( (NSSATAV *)NULL == rv ) {
1796 return (NSSATAV *)NULL;
1799 rv->oid = atav->oid;
1800 rv->stringForm = atav->stringForm;
1801 rv->value = nssUTF8_Duplicate(atav->value, arenaOpt);
1802 if( (NSSUTF8 *)NULL == rv->value ) {
1803 (void)nss_ZFreeIf(rv);
1804 return (NSSATAV *)NULL;
1807 rv->ber.data = nss_ZAlloc(arenaOpt, atav->ber.size);
1808 if( (void *)NULL == rv->ber.data ) {
1809 (void)nss_ZFreeIf(rv->value);
1810 (void)nss_ZFreeIf(rv);
1811 return (NSSATAV *)NULL;
1814 rv->ber.size = atav->ber.size;
1815 if( NULL == nsslibc_memcpy(rv->ber.data, atav->ber.data,
1816 atav->ber.size) ) {
1817 (void)nss_ZFreeIf(rv->ber.data);
1818 (void)nss_ZFreeIf(rv->value);
1819 (void)nss_ZFreeIf(rv);
1820 return (NSSATAV *)NULL;
1823 return rv;