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
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.
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 ***** */
38 static const char CVS_ID
[] = "@(#) $RCSfile: atav.c,v $ $Revision: 1.8 $ $Date: 2005/01/20 02:25:49 $";
44 * This file contains the implementation of the PKIX part-1 object
45 * AttributeTypeAndValue.
50 #endif /* NSSBASE_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 {
74 * &id OBJECT IDENTIFIER UNIQUE }
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
91 nssStringType stringForm
;
97 * The public "methods" regarding this "object" are:
99 * NSSATAV_CreateFromBER -- constructor
100 * NSSATAV_CreateFromUTF8 -- constructor
101 * NSSATAV_Create -- constructor
104 * NSSATAV_GetDEREncoding
105 * NSSATAV_GetUTF8Encoding
111 * The non-public "methods" regarding this "object" are:
113 * nssATAV_CreateFromBER -- constructor
114 * nssATAV_CreateFromUTF8 -- constructor
115 * nssATAV_Create -- constructor
118 * nssATAV_GetDEREncoding
119 * nssATAV_GetUTF8Encoding
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
145 * A pointer to an NSSATAV upon success
148 NSS_IMPLEMENT NSSATAV
*
149 NSSATAV_CreateFromBER
155 nss_ClearErrorStack();
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
;
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
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
200 * A pointer to an NSSATAV upon success
203 NSS_IMPLEMENT NSSATAV
*
204 NSSATAV_CreateFromUTF8
210 nss_ClearErrorStack();
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
;
230 return nssATAV_CreateFromUTF8(arenaOpt
, stringATAV
);
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
252 * A pointer to an NSSATAV upon success
255 NSS_IMPLEMENT NSSATAV
*
264 nss_ClearErrorStack();
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
;
283 return nssATAV_Create(arenaOpt
, oid
, data
, length
);
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
300 * PR_FAILURE upon error
301 * PR_SUCCESS upon success
304 NSS_IMPLEMENT PRStatus
310 nss_ClearErrorStack();
313 if( PR_SUCCESS
!= nssATAV_verifyPointer(atav
) ) {
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
336 * The DER encoding of this NSSATAV
339 NSS_IMPLEMENT NSSDER
*
340 NSSATAV_GetDEREncoding
346 nss_ClearErrorStack();
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
;
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
379 * A pointer to a UTF8 string containing the "equals" encoding of the
383 NSS_IMPLEMENT NSSUTF8
*
384 NSSATAV_GetUTF8Encoding
390 nss_ClearErrorStack();
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
;
404 return nssATAV_GetUTF8Encoding(atav
, arenaOpt
);
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
418 * NSS_OID_UNKNOWN upon error
419 * An element of enum NSSOIDenum upon success
422 NSS_IMPLEMENT
const NSSOID
*
428 nss_ClearErrorStack();
431 if( PR_SUCCESS
!= nssATAV_verifyPointer(atav
) ) {
432 return (NSSOID
*)NULL
;
436 return nssATAV_GetType(atav
);
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
454 * A pointer to an NSSItem containing the attribute value.
457 NSS_IMPLEMENT NSSUTF8
*
464 nss_ClearErrorStack();
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
;
478 return nssATAV_GetValue(atav
, arenaOpt
);
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
492 * The error may be one of the following values:
493 * NSS_ERROR_INVALID_ATAV
494 * NSS_ERROR_INVALID_ARGUMENT
497 * PR_FAILURE on error
498 * PR_SUCCESS upon a successful comparison (equal or not)
501 NSS_IMPLEMENT PRStatus
509 nss_ClearErrorStack();
512 if( PR_SUCCESS
!= nssATAV_verifyPointer(atav1
) ) {
516 if( PR_SUCCESS
!= nssATAV_verifyPointer(atav2
) ) {
520 if( (PRBool
*)NULL
== equalp
) {
521 nss_SetError(NSS_ERROR_INVALID_ARGUMENT
);
526 return nssATAV_Compare(atav1
, atav2
, equalp
);
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
544 * A pointer to a new ATAV
547 NSS_IMPLEMENT NSSATAV
*
554 nss_ClearErrorStack();
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
;
568 return nssATAV_Duplicate(atav
, arenaOpt
);
572 * The pointer-tracking code
576 extern const NSSError NSS_ERROR_INTERNAL_ERROR
;
578 static nssPointerTracker atav_pointer_tracker
;
588 rv
= nssPointerTracker_initialize(&atav_pointer_tracker
);
589 if( PR_SUCCESS
!= 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
);
614 rv
= nssPointerTracker_remove(&atav_pointer_tracker
, atav
);
615 if( PR_SUCCESS
!= rv
) {
616 nss_SetError(NSS_ERROR_INTERNAL_ERROR
);
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
636 * PR_SUCCESS if the pointer is valid
637 * PR_FAILURE if it isn't
640 NSS_IMPLEMENT PRStatus
641 nssATAV_verifyPointer
648 rv
= nssPointerTracker_initialize(&atav_pointer_tracker
);
649 if( PR_SUCCESS
!= rv
) {
653 rv
= nssPointerTracker_verify(&atav_pointer_tracker
, atav
);
654 if( PR_SUCCESS
!= rv
) {
655 nss_SetError(NSS_ERROR_INVALID_ATAV
);
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 },
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
{
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.
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]));
728 nss_attr_underlying_string_form
734 if( nssStringType_DirectoryString
== type
) {
735 PRUint8 tag
= *(PRUint8
*)data
;
736 switch( tag
& nssASN1_TAGNUM_MASK
) {
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
;
744 return nssStringType_PrintableString
;
746 return nssStringType_UniversalString
;
748 return nssStringType_BMPString
;
750 return nssStringType_UTF8String
;
752 return nssStringType_Unknown
;
761 * This routine decodes the attribute value, in a type-specific way.
771 nssStringType
*stringForm
774 NSSUTF8
*rv
= (NSSUTF8
*)NULL
;
776 const struct nss_attribute_data_str
*which
=
777 (struct nss_attribute_data_str
*)NULL
;
780 for( i
= 0; i
< nss_attribute_data_quantity
; i
++ ) {
781 if( *(nss_attribute_data
[ i
].oid
) == oid
) {
782 which
= &nss_attribute_data
[i
];
787 if( (struct nss_attribute_data_str
*)NULL
== which
) {
788 /* Unknown OID. Encode it as hex. */
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
;
805 *c
++ = '#'; /* XXX fgmr check this */
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 */
817 rv
= nssUTF8_CreateFromBER(arenaOpt
, which
->stringType
,
820 if( (NSSUTF8
*)NULL
== rv
) {
821 return (NSSUTF8
*)NULL
;
824 len
= nssUTF8_Length(rv
, &status
);
825 if( PR_SUCCESS
!= status
|| len
== 0 ) {
827 return (NSSUTF8
*)NULL
;
830 *stringForm
= nss_attr_underlying_string_form(which
->stringType
,
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
852 * A pointer to an NSSATAV upon success
855 NSS_IMPLEMENT NSSATAV
*
856 nssATAV_CreateFromBER
859 const NSSBER
*berATAV
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
) {
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
) {
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
,
924 if( (NSSUTF8
*)NULL
== rv
->value
) {
925 nss_ZFreeIf(rv
->ber
.data
);
927 nss_ZFreeIf(holder
.value
.data
);
928 return (NSSATAV
*)NULL
;
931 nss_ZFreeIf(holder
.value
.data
);
934 if( PR_SUCCESS
!= atav_add_pointer(rv
) ) {
935 nss_ZFreeIf(rv
->ber
.data
);
936 nss_ZFreeIf(rv
->value
);
938 return (NSSATAV
*)NULL
;
946 nss_atav_utf8_string_is_hex
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')) ) {
976 rv
= (d
[0] - '0') * 16;
977 } else if( d
[0] >= 'a' ) {
978 rv
= (d
[0] - 'a' + 10) * 16;
980 rv
= (d
[0] - 'A' + 10);
985 } else if( d
[1] >= 'a' ) {
986 rv
+= (d
[1] - 'a' + 10);
988 rv
+= (d
[1] - 'A' + 10);
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
1011 * A pointer to an NSSATAV upon success
1014 extern const NSSError NSS_ERROR_INTERNAL_ERROR
;
1016 NSS_IMPLEMENT NSSATAV
*
1017 nssATAV_CreateFromUTF8
1020 const NSSUTF8
*stringATAV
1027 const NSSOID
*oid
= (NSSOID
*)NULL
;
1031 xitem
.data
= (void *)NULL
;
1033 for( c
= (char *)stringATAV
; '\0' != *c
; c
++ ) {
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
;
1044 if( '\\' == c
[-1] ) {
1048 #endif /* PEDANTIC */
1054 nss_SetError(NSS_ERROR_INVALID_UTF8
);
1055 return (NSSATAV
*)NULL
;
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
) {
1074 return (NSSATAV
*)NULL
;
1077 for( i
= 0; i
< nss_attribute_type_alias_count
; i
++ ) {
1079 const nssAttributeTypeAliasTable
*e
= &nss_attribute_type_aliases
[i
];
1080 PRBool match
= nssUTF8_CaseIgnoreMatch(type
, e
->alias
, &status
);
1081 if( PR_SUCCESS
!= status
) {
1083 return (NSSATAV
*)NULL
;
1085 if( PR_TRUE
== match
) {
1091 if( (NSSOID
*)NULL
== oid
) {
1093 nss_SetError(NSS_ERROR_UNKNOWN_ATTRIBUTE
);
1094 return (NSSATAV
*)NULL
;
1099 type
= (NSSUTF8
*)NULL
;
1101 rv
= nss_ZNEW(arenaOpt
, NSSATAV
);
1102 if( (NSSATAV
*)NULL
== rv
) {
1103 return (NSSATAV
*)NULL
;
1108 if( '#' == *value
) { /* XXX fgmr.. was it '#'? or backslash? */
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) ) {
1139 (void)nss_ZFreeIf(rv
);
1140 nss_SetError(NSS_ERROR_INVALID_STRING
);
1141 return (NSSATAV
*)NULL
;
1146 rv
->value
= (NSSUTF8
*)nss_ZAlloc(arenaOpt
, len
+1);
1147 if( (NSSUTF8
*)NULL
== rv
->value
) {
1148 (void)nss_ZFreeIf(rv
);
1149 return (NSSATAV
*)NULL
;
1153 xitem
.data
= (void *)rv
->value
;
1155 for( c
= rv
->value
, d
= value
; len
--; c
++, d
+= 2 ) {
1156 *c
= nss_atav_fromhex(d
);
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
;
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
];
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
;
1252 PRUint32 length
= 0;
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
;
1285 rv
->stringForm
= which
->stringType
;
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
);
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
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
1328 * A pointer to an NSSATAV upon success
1331 NSS_IMPLEMENT NSSATAV
*
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
;
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
1375 * PR_FAILURE upon error
1376 * PR_SUCCESS upon success
1379 NSS_IMPLEMENT PRStatus
1386 if( PR_SUCCESS
!= nssATAV_verifyPointer(atav
) ) {
1389 #endif /* NSSDEBUG */
1391 (void)nss_ZFreeIf(atav
->ber
.data
);
1392 (void)nss_ZFreeIf(atav
->value
);
1395 if( PR_SUCCESS
!= atav_remove_pointer(atav
) ) {
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
1418 * The DER encoding of this NSSATAV
1421 NSS_IMPLEMENT NSSDER
*
1422 nssATAV_GetDEREncoding
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
;
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
1473 * A pointer to a UTF8 string containing the "equals" encoding of the
1477 NSS_IMPLEMENT NSSUTF8
*
1478 nssATAV_GetUTF8Encoding
1486 const NSSUTF8
*alias
= (NSSUTF8
*)NULL
;
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
;
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
;
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
;
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
;
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
1582 * The error may be one of the following values:
1583 * NSS_ERROR_INVALID_ATAV
1586 * NSS_OID_UNKNOWN upon error
1587 * A valid NSSOID pointer upon success
1590 NSS_IMPLEMENT
const NSSOID
*
1597 if( PR_SUCCESS
!= nssATAV_verifyPointer(atav
) ) {
1598 return (NSSOID
*)NULL
;
1600 #endif /* NSSDEBUG */
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
1615 * The error may be one of the following values:
1616 * NSS_ERROR_INVALID_ATAV
1617 * NSS_ERROR_NO_MEMORY
1621 * A pointer to an NSSItem containing the attribute value.
1624 NSS_IMPLEMENT NSSUTF8
*
1632 if( PR_SUCCESS
!= nssATAV_verifyPointer(atav
) ) {
1633 return (NSSUTF8
*)NULL
;
1635 #endif /* NSSDEBUG */
1637 return nssUTF8_Duplicate(atav
->value
, arenaOpt
);
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
1656 * PR_FAILURE on error
1657 * PR_SUCCESS upon a successful comparison (equal or not)
1660 NSS_IMPLEMENT PRStatus
1668 nssStringType comparison
;
1674 if( PR_SUCCESS
!= nssATAV_verifyPointer(atav1
) ) {
1678 if( PR_SUCCESS
!= nssATAV_verifyPointer(atav2
) ) {
1682 if( (PRBool
*)NULL
== equalp
) {
1683 nss_SetError(NSS_ERROR_INVALID_ARGUMENT
);
1688 if( atav1
->oid
!= atav2
->oid
) {
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
;
1701 comparison
= atav1
->stringForm
;
1704 comparison
= atav1
->stringForm
;
1707 switch( comparison
) {
1708 case nssStringType_DirectoryString
:
1709 nss_SetError(NSS_ERROR_INTERNAL_ERROR
);
1711 case nssStringType_TeletexString
:
1713 case nssStringType_PrintableString
:
1714 *equalp
= nssUTF8_PrintableMatch(atav1
->value
, atav2
->value
, &status
);
1716 /* Case-insensitive, with whitespace reduction */
1718 case nssStringType_UniversalString
:
1720 case nssStringType_BMPString
:
1722 case nssStringType_GeneralString
:
1723 /* what to do here? */
1725 case nssStringType_UTF8String
:
1727 case nssStringType_PHGString
:
1728 /* Case-insensitive (XXX fgmr, actually see draft-11 pg. 21) */
1729 *equalp
= nssUTF8_CaseIgnoreMatch(atav1
->value
, atav2
->value
, &status
);
1731 case nssStringType_Unknown
:
1735 len1
= nssUTF8_Size(atav1
->value
, &status
);
1736 if( PR_SUCCESS
!= status
) {
1740 len2
= nssUTF8_Size(atav2
->value
, &status
);
1741 if( PR_SUCCESS
!= status
) {
1745 if( len1
!= len2
) {
1750 *equalp
= nsslibc_memequal(atav1
->value
, atav2
->value
, len1
, &status
);
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
1770 * A pointer to a new ATAV
1773 NSS_IMPLEMENT NSSATAV
*
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
,
1817 (void)nss_ZFreeIf(rv
->ber
.data
);
1818 (void)nss_ZFreeIf(rv
->value
);
1819 (void)nss_ZFreeIf(rv
);
1820 return (NSSATAV
*)NULL
;