RetroZilla/security/nss/lib/pki1/atav.c
2015-10-20 23:03:22 -04:00

1825 lines
44 KiB
C

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape security libraries.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1994-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifdef DEBUG
static const char CVS_ID[] = "@(#) $RCSfile: atav.c,v $ $Revision: 1.8 $ $Date: 2005/01/20 02:25:49 $";
#endif /* DEBUG */
/*
* atav.c
*
* This file contains the implementation of the PKIX part-1 object
* AttributeTypeAndValue.
*/
#ifndef NSSBASE_H
#include "nssbase.h"
#endif /* NSSBASE_H */
#ifndef ASN1_H
#include "asn1.h"
#endif /* ASN1_H */
#ifndef PKI1_H
#include "pki1.h"
#endif /* PKI1_H */
/*
* AttributeTypeAndValue
*
* From draft-ietf-pkix-ipki-part1-10:
*
* AttributeTypeAndValue ::= SEQUENCE {
* type ATTRIBUTE.&id ({SupportedAttributes}),
* value ATTRIBUTE.&Type ({SupportedAttributes}{@type})}
*
* -- ATTRIBUTE information object class specification
* -- Note: This has been greatly simplified for PKIX !!
*
* ATTRIBUTE ::= CLASS {
* &Type,
* &id OBJECT IDENTIFIER UNIQUE }
* WITH SYNTAX {
* WITH SYNTAX &Type ID &id }
*
* What this means is that the "type" of the value is determined by
* the value of the oid. If we hide the structure, our accessors
* can (at least in debug builds) assert value semantics beyond what
* the compiler can provide. Since these things are only used in
* RelativeDistinguishedNames, and since RDNs always contain a SET
* of these things, we don't lose anything by hiding the structure
* (and its size).
*/
struct NSSATAVStr {
NSSBER ber;
const NSSOID *oid;
NSSUTF8 *value;
nssStringType stringForm;
};
/*
* NSSATAV
*
* The public "methods" regarding this "object" are:
*
* NSSATAV_CreateFromBER -- constructor
* NSSATAV_CreateFromUTF8 -- constructor
* NSSATAV_Create -- constructor
*
* NSSATAV_Destroy
* NSSATAV_GetDEREncoding
* NSSATAV_GetUTF8Encoding
* NSSATAV_GetType
* NSSATAV_GetValue
* NSSATAV_Compare
* NSSATAV_Duplicate
*
* The non-public "methods" regarding this "object" are:
*
* nssATAV_CreateFromBER -- constructor
* nssATAV_CreateFromUTF8 -- constructor
* nssATAV_Create -- constructor
*
* nssATAV_Destroy
* nssATAV_GetDEREncoding
* nssATAV_GetUTF8Encoding
* nssATAV_GetType
* nssATAV_GetValue
* nssATAV_Compare
* nssATAV_Duplicate
*
* In debug builds, the following non-public call is also available:
*
* nssATAV_verifyPointer
*/
/*
* NSSATAV_CreateFromBER
*
* This routine creates an NSSATAV by decoding a BER- or DER-encoded
* ATAV. If the optional arena argument is non-null, the memory used
* will be obtained from that arena; otherwise, the memory will be
* obtained from the heap. This routine may return NULL upon error,
* in which case it will have created an error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_BER
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to an NSSATAV upon success
*/
NSS_IMPLEMENT NSSATAV *
NSSATAV_CreateFromBER
(
NSSArena *arenaOpt,
NSSBER *berATAV
)
{
nss_ClearErrorStack();
#ifdef DEBUG
if( (NSSArena *)NULL != arenaOpt ) {
if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
return (NSSATAV *)NULL;
}
}
/*
* NSSBERs can be created by the user,
* so no pointer-tracking can be checked.
*/
if( (NSSBER *)NULL == berATAV ) {
nss_SetError(NSS_ERROR_INVALID_BER);
return (NSSATAV *)NULL;
}
if( (void *)NULL == berATAV->data ) {
nss_SetError(NSS_ERROR_INVALID_BER);
return (NSSATAV *)NULL;
}
#endif /* DEBUG */
return nssATAV_CreateFromBER(arenaOpt, berATAV);
}
/*
* NSSATAV_CreateFromUTF8
*
* This routine creates an NSSATAV by decoding a UTF8 string in the
* "equals" format, e.g., "c=US." If the optional arena argument is
* non-null, the memory used will be obtained from that arena;
* otherwise, the memory will be obtained from the heap. This routine
* may return NULL upon error, in which case it will have created an
* error stack.
*
* The error may be one of the following values:
* NSS_ERROR_UNKNOWN_ATTRIBUTE
* NSS_ERROR_INVALID_STRING
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to an NSSATAV upon success
*/
NSS_IMPLEMENT NSSATAV *
NSSATAV_CreateFromUTF8
(
NSSArena *arenaOpt,
NSSUTF8 *stringATAV
)
{
nss_ClearErrorStack();
#ifdef DEBUG
if( (NSSArena *)NULL != arenaOpt ) {
if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
return (NSSATAV *)NULL;
}
}
/*
* NSSUTF8s can be created by the user,
* so no pointer-tracking can be checked.
*/
if( (NSSUTF8 *)NULL == stringATAV ) {
nss_SetError(NSS_ERROR_INVALID_UTF8);
return (NSSATAV *)NULL;
}
#endif /* DEBUG */
return nssATAV_CreateFromUTF8(arenaOpt, stringATAV);
}
/*
* NSSATAV_Create
*
* This routine creates an NSSATAV from the specified NSSOID and the
* specified data. If the optional arena argument is non-null, the
* memory used will be obtained from that arena; otherwise, the memory
* will be obtained from the heap.If the specified data length is zero,
* the data is assumed to be terminated by first zero byte; this allows
* UTF8 strings to be easily specified. This routine may return NULL
* upon error, in which case it will have created an error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ARENA
* NSS_ERROR_INVALID_NSSOID
* NSS_ERROR_INVALID_POINTER
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to an NSSATAV upon success
*/
NSS_IMPLEMENT NSSATAV *
NSSATAV_Create
(
NSSArena *arenaOpt,
const NSSOID *oid,
const void *data,
PRUint32 length
)
{
nss_ClearErrorStack();
#ifdef DEBUG
if( (NSSArena *)NULL != arenaOpt ) {
if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
return (NSSATAV *)NULL;
}
}
if( PR_SUCCESS != nssOID_verifyPointer(oid) ) {
return (NSSATAV *)NULL;
}
if( (const void *)NULL == data ) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return (NSSATAV *)NULL;
}
#endif /* DEBUG */
return nssATAV_Create(arenaOpt, oid, data, length);
}
/*
* NSSATAV_Destroy
*
* This routine will destroy an ATAV object. It should eventually be
* called on all ATAVs created without an arena. While it is not
* necessary to call it on ATAVs created within an arena, it is not an
* error to do so. This routine returns a PRStatus value; if
* successful, it will return PR_SUCCESS. If unsuccessful, it will
* create an error stack and return PR_FAILURE.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
*
* Return value:
* PR_FAILURE upon error
* PR_SUCCESS upon success
*/
NSS_IMPLEMENT PRStatus
NSSATAV_Destroy
(
NSSATAV *atav
)
{
nss_ClearErrorStack();
#ifdef DEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
return PR_FAILURE;
}
#endif /* DEBUG */
return nssATAV_Destroy(atav);
}
/*
* NSSATAV_GetDEREncoding
*
* This routine will DER-encode an ATAV object. If the optional arena
* argument is non-null, the memory used will be obtained from that
* arena; otherwise, the memory will be obtained from the heap. This
* routine may return null upon error, in which case it will have
* created an error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* The DER encoding of this NSSATAV
*/
NSS_IMPLEMENT NSSDER *
NSSATAV_GetDEREncoding
(
NSSATAV *atav,
NSSArena *arenaOpt
)
{
nss_ClearErrorStack();
#ifdef DEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
return (NSSDER *)NULL;
}
if( (NSSArena *)NULL != arenaOpt ) {
if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
return (NSSDER *)NULL;
}
}
#endif /* DEBUG */
return nssATAV_GetDEREncoding(atav, arenaOpt);
}
/*
* NSSATAV_GetUTF8Encoding
*
* This routine returns a UTF8 string containing a string
* representation of the ATAV in "equals" notation (e.g., "o=Acme").
* If the optional arena argument is non-null, the memory used will be
* obtained from that arena; otherwise, the memory will be obtained
* from the heap. This routine may return null upon error, in which
* case it will have created an error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to a UTF8 string containing the "equals" encoding of the
* ATAV
*/
NSS_IMPLEMENT NSSUTF8 *
NSSATAV_GetUTF8Encoding
(
NSSATAV *atav,
NSSArena *arenaOpt
)
{
nss_ClearErrorStack();
#ifdef DEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
return (NSSUTF8 *)NULL;
}
if( (NSSArena *)NULL != arenaOpt ) {
if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
return (NSSUTF8 *)NULL;
}
}
#endif /* DEBUG */
return nssATAV_GetUTF8Encoding(atav, arenaOpt);
}
/*
* NSSATAV_GetType
*
* This routine returns the NSSOID corresponding to the attribute type
* in the specified ATAV. This routine may return NSS_OID_UNKNOWN
* upon error, in which case it will have created an error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
*
* Return value:
* NSS_OID_UNKNOWN upon error
* An element of enum NSSOIDenum upon success
*/
NSS_IMPLEMENT const NSSOID *
NSSATAV_GetType
(
NSSATAV *atav
)
{
nss_ClearErrorStack();
#ifdef DEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
return (NSSOID *)NULL;
}
#endif /* DEBUG */
return nssATAV_GetType(atav);
}
/*
* NSSATAV_GetValue
*
* This routine returns a string containing the attribute value
* in the specified ATAV. If the optional arena argument is non-null,
* the memory used will be obtained from that arena; otherwise, the
* memory will be obtained from the heap. This routine may return
* NULL upon error, in which case it will have created an error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to an NSSItem containing the attribute value.
*/
NSS_IMPLEMENT NSSUTF8 *
NSSATAV_GetValue
(
NSSATAV *atav,
NSSArena *arenaOpt
)
{
nss_ClearErrorStack();
#ifdef DEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
return (NSSUTF8 *)NULL;
}
if( (NSSArena *)NULL != arenaOpt ) {
if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
return (NSSUTF8 *)NULL;
}
}
#endif /* DEBUG */
return nssATAV_GetValue(atav, arenaOpt);
}
/*
* NSSATAV_Compare
*
* This routine compares two ATAVs for equality. For two ATAVs to be
* equal, the attribute types must be the same, and the attribute
* values must have equal length and contents. The result of the
* comparison will be stored at the location pointed to by the "equalp"
* variable, which must point to a valid PRBool. This routine may
* return PR_FAILURE upon error, in which case it will have created an
* error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
* NSS_ERROR_INVALID_ARGUMENT
*
* Return value:
* PR_FAILURE on error
* PR_SUCCESS upon a successful comparison (equal or not)
*/
NSS_IMPLEMENT PRStatus
NSSATAV_Compare
(
NSSATAV *atav1,
NSSATAV *atav2,
PRBool *equalp
)
{
nss_ClearErrorStack();
#ifdef DEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav1) ) {
return PR_FAILURE;
}
if( PR_SUCCESS != nssATAV_verifyPointer(atav2) ) {
return PR_FAILURE;
}
if( (PRBool *)NULL == equalp ) {
nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
return PR_FAILURE;
}
#endif /* DEBUG */
return nssATAV_Compare(atav1, atav2, equalp);
}
/*
* NSSATAV_Duplicate
*
* This routine duplicates the specified ATAV. If the optional arena
* argument is non-null, the memory required will be obtained from
* that arena; otherwise, the memory will be obtained from the heap.
* This routine may return NULL upon error, in which case it will have
* created an error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL on error
* A pointer to a new ATAV
*/
NSS_IMPLEMENT NSSATAV *
NSSATAV_Duplicate
(
NSSATAV *atav,
NSSArena *arenaOpt
)
{
nss_ClearErrorStack();
#ifdef DEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
return (NSSATAV *)NULL;
}
if( (NSSArena *)NULL != arenaOpt ) {
if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
return (NSSATAV *)NULL;
}
}
#endif /* DEBUG */
return nssATAV_Duplicate(atav, arenaOpt);
}
/*
* The pointer-tracking code
*/
#ifdef DEBUG
extern const NSSError NSS_ERROR_INTERNAL_ERROR;
static nssPointerTracker atav_pointer_tracker;
static PRStatus
atav_add_pointer
(
const NSSATAV *atav
)
{
PRStatus rv;
rv = nssPointerTracker_initialize(&atav_pointer_tracker);
if( PR_SUCCESS != rv ) {
return rv;
}
rv = nssPointerTracker_add(&atav_pointer_tracker, atav);
if( PR_SUCCESS != rv ) {
NSSError e = NSS_GetError();
if( NSS_ERROR_NO_MEMORY != e ) {
nss_SetError(NSS_ERROR_INTERNAL_ERROR);
}
return rv;
}
return PR_SUCCESS;
}
static PRStatus
atav_remove_pointer
(
const NSSATAV *atav
)
{
PRStatus rv;
rv = nssPointerTracker_remove(&atav_pointer_tracker, atav);
if( PR_SUCCESS != rv ) {
nss_SetError(NSS_ERROR_INTERNAL_ERROR);
}
return rv;
}
/*
* nssATAV_verifyPointer
*
* This method is only present in debug builds.
*
* If the specified pointer is a valid pointer to an NSSATAV object,
* this routine will return PR_SUCCESS. Otherwise, it will put an
* error on the error stack and return PR_FAILRUE.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_NSSATAV
* NSS_ERROR_NO_MEMORY
*
* Return value:
* PR_SUCCESS if the pointer is valid
* PR_FAILURE if it isn't
*/
NSS_IMPLEMENT PRStatus
nssATAV_verifyPointer
(
NSSATAV *atav
)
{
PRStatus rv;
rv = nssPointerTracker_initialize(&atav_pointer_tracker);
if( PR_SUCCESS != rv ) {
return PR_FAILURE;
}
rv = nssPointerTracker_verify(&atav_pointer_tracker, atav);
if( PR_SUCCESS != rv ) {
nss_SetError(NSS_ERROR_INVALID_ATAV);
return PR_FAILURE;
}
return PR_SUCCESS;
}
#endif /* DEBUG */
typedef struct {
NSSBER oid;
NSSBER value;
} atav_holder;
static const nssASN1Template nss_atav_template[] = {
{ nssASN1_SEQUENCE, 0, NULL, sizeof(atav_holder) },
{ nssASN1_OBJECT_ID, nsslibc_offsetof(atav_holder, oid), NULL, 0 },
{ nssASN1_ANY, nsslibc_offsetof(atav_holder, value), NULL, 0 },
{ 0, 0, NULL, 0 }
};
/*
* There are several common attributes, with well-known type aliases
* and value semantics. This table lists the ones we recognize.
*/
struct nss_attribute_data_str {
const NSSOID **oid;
nssStringType stringType;
PRUint32 minStringLength;
PRUint32 maxStringLength; /* zero for no limit */
};
static const struct nss_attribute_data_str nss_attribute_data[] = {
{ &NSS_OID_X520_NAME,
nssStringType_DirectoryString, 1, 32768 },
{ &NSS_OID_X520_COMMON_NAME,
nssStringType_DirectoryString, 1, 64 },
{ &NSS_OID_X520_SURNAME,
nssStringType_DirectoryString, 1, 40 },
{ &NSS_OID_X520_GIVEN_NAME,
nssStringType_DirectoryString, 1, 16 },
{ &NSS_OID_X520_INITIALS,
nssStringType_DirectoryString, 1, 5 },
{ &NSS_OID_X520_GENERATION_QUALIFIER,
nssStringType_DirectoryString, 1, 3 },
{ &NSS_OID_X520_DN_QUALIFIER,
nssStringType_PrintableString, 1, 0 },
{ &NSS_OID_X520_COUNTRY_NAME,
nssStringType_PrintableString, 2, 2 },
{ &NSS_OID_X520_LOCALITY_NAME,
nssStringType_DirectoryString, 1, 128 },
{ &NSS_OID_X520_STATE_OR_PROVINCE_NAME,
nssStringType_DirectoryString, 1, 128 },
{ &NSS_OID_X520_ORGANIZATION_NAME,
nssStringType_DirectoryString, 1, 64 },
{ &NSS_OID_X520_ORGANIZATIONAL_UNIT_NAME,
nssStringType_DirectoryString, 1,
/*
* Note, draft #11 defines both "32" and "64" for this maximum,
* in two separate places. Until it's settled, "conservative
* in what you send." We're always liberal in what we accept.
*/
32 },
{ &NSS_OID_X520_TITLE,
nssStringType_DirectoryString, 1, 64 },
{ &NSS_OID_RFC1274_EMAIL,
nssStringType_PHGString, 1, 128 }
};
PRUint32 nss_attribute_data_quantity =
(sizeof(nss_attribute_data)/sizeof(nss_attribute_data[0]));
static nssStringType
nss_attr_underlying_string_form
(
nssStringType type,
void *data
)
{
if( nssStringType_DirectoryString == type ) {
PRUint8 tag = *(PRUint8 *)data;
switch( tag & nssASN1_TAGNUM_MASK ) {
case 20:
/*
* XXX fgmr-- we have to accept Latin-1 for Teletex; (see
* below) but is T61 a suitable value for "Latin-1"?
*/
return nssStringType_TeletexString;
case 19:
return nssStringType_PrintableString;
case 28:
return nssStringType_UniversalString;
case 30:
return nssStringType_BMPString;
case 12:
return nssStringType_UTF8String;
default:
return nssStringType_Unknown;
}
}
return type;
}
/*
* This routine decodes the attribute value, in a type-specific way.
*
*/
static NSSUTF8 *
nss_attr_to_utf8
(
NSSArena *arenaOpt,
const NSSOID *oid,
NSSItem *item,
nssStringType *stringForm
)
{
NSSUTF8 *rv = (NSSUTF8 *)NULL;
PRUint32 i;
const struct nss_attribute_data_str *which =
(struct nss_attribute_data_str *)NULL;
PRUint32 len = 0;
for( i = 0; i < nss_attribute_data_quantity; i++ ) {
if( *(nss_attribute_data[ i ].oid) == oid ) {
which = &nss_attribute_data[i];
break;
}
}
if( (struct nss_attribute_data_str *)NULL == which ) {
/* Unknown OID. Encode it as hex. */
PRUint8 *c;
PRUint8 *d = (PRUint8 *)item->data;
PRUint32 amt = item->size;
if( item->size >= 0x7FFFFFFF ) {
nss_SetError(NSS_ERROR_INVALID_STRING);
return (NSSUTF8 *)NULL;
}
len = 1 + (item->size * 2) + 1; /* '#' + hex + '\0' */
rv = (NSSUTF8 *)nss_ZAlloc(arenaOpt, len);
if( (NSSUTF8 *)NULL == rv ) {
return (NSSUTF8 *)NULL;
}
c = (PRUint8 *)rv;
*c++ = '#'; /* XXX fgmr check this */
while( amt > 0 ) {
static char hex[16] = "0123456789ABCDEF";
*c++ = hex[ ((*d) & 0xf0) >> 4 ];
*c++ = hex[ ((*d) & 0x0f) ];
}
/* *c = '\0'; nss_ZAlloc, remember */
*stringForm = nssStringType_Unknown; /* force exact comparison */
} else {
PRStatus status;
rv = nssUTF8_CreateFromBER(arenaOpt, which->stringType,
(NSSBER *)item);
if( (NSSUTF8 *)NULL == rv ) {
return (NSSUTF8 *)NULL;
}
len = nssUTF8_Length(rv, &status);
if( PR_SUCCESS != status || len == 0 ) {
nss_ZFreeIf(rv);
return (NSSUTF8 *)NULL;
}
*stringForm = nss_attr_underlying_string_form(which->stringType,
item->data);
}
return rv;
}
/*
* nssATAV_CreateFromBER
*
* This routine creates an NSSATAV by decoding a BER- or DER-encoded
* ATAV. If the optional arena argument is non-null, the memory used
* will be obtained from that arena; otherwise, the memory will be
* obtained from the heap. This routine may return NULL upon error,
* in which case it will have set an error on the error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_BER
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to an NSSATAV upon success
*/
NSS_IMPLEMENT NSSATAV *
nssATAV_CreateFromBER
(
NSSArena *arenaOpt,
const NSSBER *berATAV
)
{
atav_holder holder;
PRStatus status;
NSSATAV *rv;
#ifdef NSSDEBUG
if( (NSSArena *)NULL != arenaOpt ) {
if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
return (NSSATAV *)NULL;
}
}
/*
* NSSBERs can be created by the user,
* so no pointer-tracking can be checked.
*/
if( (NSSBER *)NULL == berATAV ) {
nss_SetError(NSS_ERROR_INVALID_BER);
return (NSSATAV *)NULL;
}
if( (void *)NULL == berATAV->data ) {
nss_SetError(NSS_ERROR_INVALID_BER);
return (NSSATAV *)NULL;
}
#endif /* NSSDEBUG */
status = nssASN1_DecodeBER(arenaOpt, &holder,
nss_atav_template, berATAV);
if( PR_SUCCESS != status ) {
return (NSSATAV *)NULL;
}
rv = nss_ZNEW(arenaOpt, NSSATAV);
if( (NSSATAV *)NULL == rv ) {
nss_ZFreeIf(holder.oid.data);
nss_ZFreeIf(holder.value.data);
return (NSSATAV *)NULL;
}
rv->oid = nssOID_CreateFromBER(&holder.oid);
if( (NSSOID *)NULL == rv->oid ) {
nss_ZFreeIf(rv);
nss_ZFreeIf(holder.oid.data);
nss_ZFreeIf(holder.value.data);
return (NSSATAV *)NULL;
}
nss_ZFreeIf(holder.oid.data);
rv->ber.data = nss_ZAlloc(arenaOpt, berATAV->size);
if( (void *)NULL == rv->ber.data ) {
nss_ZFreeIf(rv);
nss_ZFreeIf(holder.value.data);
return (NSSATAV *)NULL;
}
rv->ber.size = berATAV->size;
(void)nsslibc_memcpy(rv->ber.data, berATAV->data, berATAV->size);
rv->value = nss_attr_to_utf8(arenaOpt, rv->oid, &holder.value,
&rv->stringForm);
if( (NSSUTF8 *)NULL == rv->value ) {
nss_ZFreeIf(rv->ber.data);
nss_ZFreeIf(rv);
nss_ZFreeIf(holder.value.data);
return (NSSATAV *)NULL;
}
nss_ZFreeIf(holder.value.data);
#ifdef DEBUG
if( PR_SUCCESS != atav_add_pointer(rv) ) {
nss_ZFreeIf(rv->ber.data);
nss_ZFreeIf(rv->value);
nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
#endif /* DEBUG */
return rv;
}
static PRBool
nss_atav_utf8_string_is_hex
(
const NSSUTF8 *s
)
{
/* All hex digits are ASCII, so this works */
PRUint8 *p = (PRUint8 *)s;
for( ; (PRUint8)0 != *p; p++ ) {
if( (('0' <= *p) && (*p <= '9')) ||
(('A' <= *p) && (*p <= 'F')) ||
(('a' <= *p) && (*p <= 'f')) ) {
continue;
} else {
return PR_FALSE;
}
}
return PR_TRUE;
}
static NSSUTF8
nss_atav_fromhex
(
NSSUTF8 *d
)
{
NSSUTF8 rv;
if( d[0] <= '9' ) {
rv = (d[0] - '0') * 16;
} else if( d[0] >= 'a' ) {
rv = (d[0] - 'a' + 10) * 16;
} else {
rv = (d[0] - 'A' + 10);
}
if( d[1] <= '9' ) {
rv += (d[1] - '0');
} else if( d[1] >= 'a' ) {
rv += (d[1] - 'a' + 10);
} else {
rv += (d[1] - 'A' + 10);
}
return rv;
}
/*
* nssATAV_CreateFromUTF8
*
* This routine creates an NSSATAV by decoding a UTF8 string in the
* "equals" format, e.g., "c=US." If the optional arena argument is
* non-null, the memory used will be obtained from that arena;
* otherwise, the memory will be obtained from the heap. This routine
* may return NULL upon error, in which case it will have set an error
* on the error stack.
*
* The error may be one of the following values:
* NSS_ERROR_UNKNOWN_ATTRIBUTE
* NSS_ERROR_INVALID_STRING
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to an NSSATAV upon success
*/
extern const NSSError NSS_ERROR_INTERNAL_ERROR;
NSS_IMPLEMENT NSSATAV *
nssATAV_CreateFromUTF8
(
NSSArena *arenaOpt,
const NSSUTF8 *stringATAV
)
{
char *c;
NSSUTF8 *type;
NSSUTF8 *value;
PRUint32 i;
const NSSOID *oid = (NSSOID *)NULL;
NSSATAV *rv;
NSSItem xitem;
xitem.data = (void *)NULL;
for( c = (char *)stringATAV; '\0' != *c; c++ ) {
if( '=' == *c ) {
#ifdef PEDANTIC
/*
* Theoretically, one could have an '=' in an
* attribute string alias. We don't, yet, though.
*/
if( (char *)stringATAV == c ) {
nss_SetError(NSS_ERROR_INVALID_STRING);
return (NSSATAV *)NULL;
} else {
if( '\\' == c[-1] ) {
continue;
}
}
#endif /* PEDANTIC */
break;
}
}
if( '\0' == *c ) {
nss_SetError(NSS_ERROR_INVALID_UTF8);
return (NSSATAV *)NULL;
} else {
c++;
value = (NSSUTF8 *)c;
}
i = ((NSSUTF8 *)c - stringATAV);
type = (NSSUTF8 *)nss_ZAlloc((NSSArena *)NULL, i);
if( (NSSUTF8 *)NULL == type ) {
return (NSSATAV *)NULL;
}
(void)nsslibc_memcpy(type, stringATAV, i-1);
c = (char *)stringATAV;
if( (('0' <= *c) && (*c <= '9')) || ('#' == *c) ) {
oid = nssOID_CreateFromUTF8(type);
if( (NSSOID *)NULL == oid ) {
nss_ZFreeIf(type);
return (NSSATAV *)NULL;
}
} else {
for( i = 0; i < nss_attribute_type_alias_count; i++ ) {
PRStatus status;
const nssAttributeTypeAliasTable *e = &nss_attribute_type_aliases[i];
PRBool match = nssUTF8_CaseIgnoreMatch(type, e->alias, &status);
if( PR_SUCCESS != status ) {
nss_ZFreeIf(type);
return (NSSATAV *)NULL;
}
if( PR_TRUE == match ) {
oid = *(e->oid);
break;
}
}
if( (NSSOID *)NULL == oid ) {
nss_ZFreeIf(type);
nss_SetError(NSS_ERROR_UNKNOWN_ATTRIBUTE);
return (NSSATAV *)NULL;
}
}
nss_ZFreeIf(type);
type = (NSSUTF8 *)NULL;
rv = nss_ZNEW(arenaOpt, NSSATAV);
if( (NSSATAV *)NULL == rv ) {
return (NSSATAV *)NULL;
}
rv->oid = oid;
if( '#' == *value ) { /* XXX fgmr.. was it '#'? or backslash? */
PRUint32 size;
PRUint32 len;
NSSUTF8 *c;
NSSUTF8 *d;
PRStatus status;
/* It's in hex */
value++;
if( PR_TRUE != nss_atav_utf8_string_is_hex(value) ) {
(void)nss_ZFreeIf(rv);
nss_SetError(NSS_ERROR_INVALID_STRING);
return (NSSATAV *)NULL;
}
size = nssUTF8_Size(value, &status);
if( PR_SUCCESS != status ) {
/*
* Only returns an error on bad pointer (nope) or string
* too long. The defined limits for known attributes are
* small enough to fit in PRUint32, and when undefined we
* get to apply our own practical limits. Ergo, I say the
* string is invalid.
*/
(void)nss_ZFreeIf(rv);
nss_SetError(NSS_ERROR_INVALID_STRING);
return (NSSATAV *)NULL;
}
if( ((size-1) & 1) ) {
/* odd length */
(void)nss_ZFreeIf(rv);
nss_SetError(NSS_ERROR_INVALID_STRING);
return (NSSATAV *)NULL;
}
len = (size-1)/2;
rv->value = (NSSUTF8 *)nss_ZAlloc(arenaOpt, len+1);
if( (NSSUTF8 *)NULL == rv->value ) {
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
xitem.size = len;
xitem.data = (void *)rv->value;
for( c = rv->value, d = value; len--; c++, d += 2 ) {
*c = nss_atav_fromhex(d);
}
*c = 0;
} else {
PRStatus status;
PRUint32 i, len;
PRUint8 *s;
/*
* XXX fgmr-- okay, this is a little wasteful, and should
* probably be abstracted out a bit. Later.
*/
rv->value = nssUTF8_Duplicate(value, arenaOpt);
if( (NSSUTF8 *)NULL == rv->value ) {
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
len = nssUTF8_Size(rv->value, &status);
if( PR_SUCCESS != status ) {
(void)nss_ZFreeIf(rv->value);
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
s = (PRUint8 *)rv->value;
for( i = 0; i < len; i++ ) {
if( '\\' == s[i] ) {
(void)nsslibc_memcpy(&s[i], &s[i+1], len-i-1);
}
}
}
/* Now just BER-encode the baby and we're through.. */
{
const struct nss_attribute_data_str *which =
(struct nss_attribute_data_str *)NULL;
PRUint32 i;
NSSArena *a;
NSSDER *oidder;
NSSItem *vitem;
atav_holder ah;
NSSDER *status;
for( i = 0; i < nss_attribute_data_quantity; i++ ) {
if( *(nss_attribute_data[ i ].oid) == rv->oid ) {
which = &nss_attribute_data[i];
break;
}
}
a = NSSArena_Create();
if( (NSSArena *)NULL == a ) {
(void)nss_ZFreeIf(rv->value);
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
oidder = nssOID_GetDEREncoding(rv->oid, (NSSDER *)NULL, a);
if( (NSSDER *)NULL == oidder ) {
(void)NSSArena_Destroy(a);
(void)nss_ZFreeIf(rv->value);
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
if( (struct nss_attribute_data_str *)NULL == which ) {
/*
* We'll just have to take the user data as an octet stream.
*/
if( (void *)NULL == xitem.data ) {
/*
* This means that an ATTR entry has been added to oids.txt,
* but no corresponding entry has been added to the array
* ns_attribute_data[] above.
*/
nss_SetError(NSS_ERROR_INTERNAL_ERROR);
(void)NSSArena_Destroy(a);
(void)nss_ZFreeIf(rv->value);
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
vitem = nssASN1_EncodeItem(a, (NSSDER *)NULL, &xitem,
nssASN1Template_OctetString, NSSASN1DER);
if( (NSSItem *)NULL == vitem ) {
(void)NSSArena_Destroy(a);
(void)nss_ZFreeIf(rv->value);
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
rv->stringForm = nssStringType_Unknown;
} else {
PRUint32 length = 0;
PRStatus stat;
length = nssUTF8_Length(rv->value, &stat);
if( PR_SUCCESS != stat ) {
(void)NSSArena_Destroy(a);
(void)nss_ZFreeIf(rv->value);
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
if( ((0 != which->minStringLength) &&
(length < which->minStringLength)) ||
((0 != which->maxStringLength) &&
(length > which->maxStringLength)) ) {
nss_SetError(NSS_ERROR_INVALID_STRING);
(void)NSSArena_Destroy(a);
(void)nss_ZFreeIf(rv->value);
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
vitem = nssUTF8_GetDEREncoding(a, which->stringType, rv->value);
if( (NSSItem *)NULL == vitem ) {
(void)NSSArena_Destroy(a);
(void)nss_ZFreeIf(rv->value);
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
if( nssStringType_DirectoryString == which->stringType ) {
rv->stringForm = nssStringType_UTF8String;
} else {
rv->stringForm = which->stringType;
}
}
ah.oid = *oidder;
ah.value = *vitem;
status = nssASN1_EncodeItem(arenaOpt, &rv->ber, &ah,
nss_atav_template, NSSASN1DER);
if( (NSSDER *)NULL == status ) {
(void)NSSArena_Destroy(a);
(void)nss_ZFreeIf(rv->value);
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
(void)NSSArena_Destroy(a);
}
return rv;
}
/*
* nssATAV_Create
*
* This routine creates an NSSATAV from the specified NSSOID and the
* specified data. If the optional arena argument is non-null, the
* memory used will be obtained from that arena; otherwise, the memory
* will be obtained from the heap.If the specified data length is zero,
* the data is assumed to be terminated by first zero byte; this allows
* UTF8 strings to be easily specified. This routine may return NULL
* upon error, in which case it will have set an error on the error
* stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ARENA
* NSS_ERROR_INVALID_NSSOID
* NSS_ERROR_INVALID_POINTER
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to an NSSATAV upon success
*/
NSS_IMPLEMENT NSSATAV *
nssATAV_Create
(
NSSArena *arenaOpt,
const NSSOID *oid,
const void *data,
PRUint32 length
)
{
#ifdef NSSDEBUG
if( (NSSArena *)NULL != arenaOpt ) {
if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
return (NSSATAV *)NULL;
}
}
if( PR_SUCCESS != nssOID_verifyPointer(oid) ) {
return (NSSATAV *)NULL;
}
if( (const void *)NULL == data ) {
nss_SetError(NSS_ERROR_INVALID_POINTER);
return (NSSATAV *)NULL;
}
#endif /* NSSDEBUG */
/* XXX fgmr-- oops, forgot this one */
return (NSSATAV *)NULL;
}
/*
* nssATAV_Destroy
*
* This routine will destroy an ATAV object. It should eventually be
* called on all ATAVs created without an arena. While it is not
* necessary to call it on ATAVs created within an arena, it is not an
* error to do so. This routine returns a PRStatus value; if
* successful, it will return PR_SUCCESS. If unsuccessful, it will
* set an error on the error stack and return PR_FAILURE.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
*
* Return value:
* PR_FAILURE upon error
* PR_SUCCESS upon success
*/
NSS_IMPLEMENT PRStatus
nssATAV_Destroy
(
NSSATAV *atav
)
{
#ifdef NSSDEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
return PR_FAILURE;
}
#endif /* NSSDEBUG */
(void)nss_ZFreeIf(atav->ber.data);
(void)nss_ZFreeIf(atav->value);
#ifdef DEBUG
if( PR_SUCCESS != atav_remove_pointer(atav) ) {
return PR_FAILURE;
}
#endif /* DEBUG */
return PR_SUCCESS;
}
/*
* nssATAV_GetDEREncoding
*
* This routine will DER-encode an ATAV object. If the optional arena
* argument is non-null, the memory used will be obtained from that
* arena; otherwise, the memory will be obtained from the heap. This
* routine may return null upon error, in which case it will have set
* an error on the error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* The DER encoding of this NSSATAV
*/
NSS_IMPLEMENT NSSDER *
nssATAV_GetDEREncoding
(
NSSATAV *atav,
NSSArena *arenaOpt
)
{
NSSDER *rv;
#ifdef NSSDEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
return (NSSDER *)NULL;
}
#endif /* NSSDEBUG */
rv = nss_ZNEW(arenaOpt, NSSDER);
if( (NSSDER *)NULL == rv ) {
return (NSSDER *)NULL;
}
rv->data = nss_ZAlloc(arenaOpt, atav->ber.size);
if( (void *)NULL == rv->data ) {
(void)nss_ZFreeIf(rv);
return (NSSDER *)NULL;
}
rv->size = atav->ber.size;
if( NULL == nsslibc_memcpy(rv->data, atav->ber.data, rv->size) ) {
(void)nss_ZFreeIf(rv->data);
(void)nss_ZFreeIf(rv);
return (NSSDER *)NULL;
}
return rv;
}
/*
* nssATAV_GetUTF8Encoding
*
* This routine returns a UTF8 string containing a string
* representation of the ATAV in "equals" notation (e.g., "o=Acme").
* If the optional arena argument is non-null, the memory used will be
* obtained from that arena; otherwise, the memory will be obtained
* from the heap. This routine may return null upon error, in which
* case it will have set an error on the error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to a UTF8 string containing the "equals" encoding of the
* ATAV
*/
NSS_IMPLEMENT NSSUTF8 *
nssATAV_GetUTF8Encoding
(
NSSATAV *atav,
NSSArena *arenaOpt
)
{
NSSUTF8 *rv;
PRUint32 i;
const NSSUTF8 *alias = (NSSUTF8 *)NULL;
NSSUTF8 *oid;
NSSUTF8 *value;
PRUint32 oidlen;
PRUint32 valuelen;
PRUint32 totallen;
PRStatus status;
#ifdef NSSDEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
return (NSSUTF8 *)NULL;
}
#endif /* NSSDEBUG */
for( i = 0; i < nss_attribute_type_alias_count; i++ ) {
if( *(nss_attribute_type_aliases[i].oid) == atav->oid ) {
alias = nss_attribute_type_aliases[i].alias;
break;
}
}
if( (NSSUTF8 *)NULL == alias ) {
oid = nssOID_GetUTF8Encoding(atav->oid, (NSSArena *)NULL);
if( (NSSUTF8 *)NULL == oid ) {
return (NSSUTF8 *)NULL;
}
oidlen = nssUTF8_Size(oid, &status);
if( PR_SUCCESS != status ) {
(void)nss_ZFreeIf(oid);
return (NSSUTF8 *)NULL;
}
} else {
oidlen = nssUTF8_Size(alias, &status);
if( PR_SUCCESS != status ) {
return (NSSUTF8 *)NULL;
}
oid = (NSSUTF8 *)NULL;
}
value = nssATAV_GetValue(atav, (NSSArena *)NULL);
if( (NSSUTF8 *)NULL == value ) {
(void)nss_ZFreeIf(oid);
return (NSSUTF8 *)NULL;
}
valuelen = nssUTF8_Size(value, &status);
if( PR_SUCCESS != status ) {
(void)nss_ZFreeIf(value);
(void)nss_ZFreeIf(oid);
return (NSSUTF8 *)NULL;
}
totallen = oidlen + valuelen - 1 + 1;
rv = (NSSUTF8 *)nss_ZAlloc(arenaOpt, totallen);
if( (NSSUTF8 *)NULL == rv ) {
(void)nss_ZFreeIf(value);
(void)nss_ZFreeIf(oid);
return (NSSUTF8 *)NULL;
}
if( (NSSUTF8 *)NULL == alias ) {
if( (void *)NULL == nsslibc_memcpy(rv, oid, oidlen-1) ) {
(void)nss_ZFreeIf(rv);
(void)nss_ZFreeIf(value);
(void)nss_ZFreeIf(oid);
return (NSSUTF8 *)NULL;
}
} else {
if( (void *)NULL == nsslibc_memcpy(rv, alias, oidlen-1) ) {
(void)nss_ZFreeIf(rv);
(void)nss_ZFreeIf(value);
return (NSSUTF8 *)NULL;
}
}
rv[ oidlen-1 ] = '=';
if( (void *)NULL == nsslibc_memcpy(&rv[oidlen], value, valuelen) ) {
(void)nss_ZFreeIf(rv);
(void)nss_ZFreeIf(value);
(void)nss_ZFreeIf(oid);
return (NSSUTF8 *)NULL;
}
return rv;
}
/*
* nssATAV_GetType
*
* This routine returns the NSSOID corresponding to the attribute type
* in the specified ATAV. This routine may return NSS_OID_UNKNOWN
* upon error, in which case it will have set an error on the error
* stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
*
* Return value:
* NSS_OID_UNKNOWN upon error
* A valid NSSOID pointer upon success
*/
NSS_IMPLEMENT const NSSOID *
nssATAV_GetType
(
NSSATAV *atav
)
{
#ifdef NSSDEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
return (NSSOID *)NULL;
}
#endif /* NSSDEBUG */
return atav->oid;
}
/*
* nssATAV_GetValue
*
* This routine returns a NSSUTF8 string containing the attribute value
* in the specified ATAV. If the optional arena argument is non-null,
* the memory used will be obtained from that arena; otherwise, the
* memory will be obtained from the heap. This routine may return
* NULL upon error, in which case it will have set an error upon the
* error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL upon error
* A pointer to an NSSItem containing the attribute value.
*/
NSS_IMPLEMENT NSSUTF8 *
nssATAV_GetValue
(
NSSATAV *atav,
NSSArena *arenaOpt
)
{
#ifdef NSSDEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
return (NSSUTF8 *)NULL;
}
#endif /* NSSDEBUG */
return nssUTF8_Duplicate(atav->value, arenaOpt);
}
/*
* nssATAV_Compare
*
* This routine compares two ATAVs for equality. For two ATAVs to be
* equal, the attribute types must be the same, and the attribute
* values must have equal length and contents. The result of the
* comparison will be stored at the location pointed to by the "equalp"
* variable, which must point to a valid PRBool. This routine may
* return PR_FAILURE upon error, in which case it will have set an
* error on the error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
* NSS_ERROR_INVALID_ARGUMENT
*
* Return value:
* PR_FAILURE on error
* PR_SUCCESS upon a successful comparison (equal or not)
*/
NSS_IMPLEMENT PRStatus
nssATAV_Compare
(
NSSATAV *atav1,
NSSATAV *atav2,
PRBool *equalp
)
{
nssStringType comparison;
PRUint32 len1;
PRUint32 len2;
PRStatus status;
#ifdef DEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav1) ) {
return PR_FAILURE;
}
if( PR_SUCCESS != nssATAV_verifyPointer(atav2) ) {
return PR_FAILURE;
}
if( (PRBool *)NULL == equalp ) {
nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
return PR_FAILURE;
}
#endif /* DEBUG */
if( atav1->oid != atav2->oid ) {
*equalp = PR_FALSE;
return PR_SUCCESS;
}
if( atav1->stringForm != atav2->stringForm ) {
if( (nssStringType_PrintableString == atav1->stringForm) ||
(nssStringType_PrintableString == atav2->stringForm) ) {
comparison = nssStringType_PrintableString;
} else if( (nssStringType_PHGString == atav1->stringForm) ||
(nssStringType_PHGString == atav2->stringForm) ) {
comparison = nssStringType_PHGString;
} else {
comparison = atav1->stringForm;
}
} else {
comparison = atav1->stringForm;
}
switch( comparison ) {
case nssStringType_DirectoryString:
nss_SetError(NSS_ERROR_INTERNAL_ERROR);
return PR_FAILURE;
case nssStringType_TeletexString:
break;
case nssStringType_PrintableString:
*equalp = nssUTF8_PrintableMatch(atav1->value, atav2->value, &status);
return status;
/* Case-insensitive, with whitespace reduction */
break;
case nssStringType_UniversalString:
break;
case nssStringType_BMPString:
break;
case nssStringType_GeneralString:
/* what to do here? */
break;
case nssStringType_UTF8String:
break;
case nssStringType_PHGString:
/* Case-insensitive (XXX fgmr, actually see draft-11 pg. 21) */
*equalp = nssUTF8_CaseIgnoreMatch(atav1->value, atav2->value, &status);
return status;
case nssStringType_Unknown:
break;
}
len1 = nssUTF8_Size(atav1->value, &status);
if( PR_SUCCESS != status ) {
return PR_FAILURE;
}
len2 = nssUTF8_Size(atav2->value, &status);
if( PR_SUCCESS != status ) {
return PR_FAILURE;
}
if( len1 != len2 ) {
*equalp = PR_FALSE;
return PR_SUCCESS;
}
*equalp = nsslibc_memequal(atav1->value, atav2->value, len1, &status);
return status;
}
/*
* nssATAV_Duplicate
*
* This routine duplicates the specified ATAV. If the optional arena
* argument is non-null, the memory required will be obtained from
* that arena; otherwise, the memory will be obtained from the heap.
* This routine may return NULL upon error, in which case it will have
* placed an error on the error stack.
*
* The error may be one of the following values:
* NSS_ERROR_INVALID_ATAV
* NSS_ERROR_NO_MEMORY
*
* Return value:
* NULL on error
* A pointer to a new ATAV
*/
NSS_IMPLEMENT NSSATAV *
nssATAV_Duplicate
(
NSSATAV *atav,
NSSArena *arenaOpt
)
{
NSSATAV *rv;
#ifdef NSSDEBUG
if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
return (NSSATAV *)NULL;
}
if( (NSSArena *)NULL != arenaOpt ) {
if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
return (NSSATAV *)NULL;
}
}
#endif /* NSSDEBUG */
rv = nss_ZNEW(arenaOpt, NSSATAV);
if( (NSSATAV *)NULL == rv ) {
return (NSSATAV *)NULL;
}
rv->oid = atav->oid;
rv->stringForm = atav->stringForm;
rv->value = nssUTF8_Duplicate(atav->value, arenaOpt);
if( (NSSUTF8 *)NULL == rv->value ) {
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
rv->ber.data = nss_ZAlloc(arenaOpt, atav->ber.size);
if( (void *)NULL == rv->ber.data ) {
(void)nss_ZFreeIf(rv->value);
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
rv->ber.size = atav->ber.size;
if( NULL == nsslibc_memcpy(rv->ber.data, atav->ber.data,
atav->ber.size) ) {
(void)nss_ZFreeIf(rv->ber.data);
(void)nss_ZFreeIf(rv->value);
(void)nss_ZFreeIf(rv);
return (NSSATAV *)NULL;
}
return rv;
}