Back to index

lightning-sunbird  0.9+nobinonly
atav.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #ifdef DEBUG
00038 static const char CVS_ID[] = "@(#) $RCSfile: atav.c,v $ $Revision: 1.8 $ $Date: 2005/01/20 02:25:49 $";
00039 #endif /* DEBUG */
00040 
00041 /*
00042  * atav.c
00043  *
00044  * This file contains the implementation of the PKIX part-1 object
00045  * AttributeTypeAndValue.
00046  */
00047 
00048 #ifndef NSSBASE_H
00049 #include "nssbase.h"
00050 #endif /* NSSBASE_H */
00051 
00052 #ifndef ASN1_H
00053 #include "asn1.h"
00054 #endif /* ASN1_H */
00055 
00056 #ifndef PKI1_H
00057 #include "pki1.h"
00058 #endif /* PKI1_H */
00059 
00060 /*
00061  * AttributeTypeAndValue
00062  *
00063  * From draft-ietf-pkix-ipki-part1-10:
00064  *
00065  *  AttributeTypeAndValue           ::=     SEQUENCE {
00066  *          type            ATTRIBUTE.&id ({SupportedAttributes}),
00067  *          value   ATTRIBUTE.&Type ({SupportedAttributes}{@type})}
00068  *  
00069  *  -- ATTRIBUTE information object class specification
00070  *  --  Note: This has been greatly simplified for PKIX !!
00071  *  
00072  *  ATTRIBUTE               ::=     CLASS {
00073  *          &Type,
00074  *          &id                     OBJECT IDENTIFIER UNIQUE }
00075  *  WITH SYNTAX {
00076  *          WITH SYNTAX &Type ID &id }
00077  *  
00078  * What this means is that the "type" of the value is determined by
00079  * the value of the oid.  If we hide the structure, our accessors
00080  * can (at least in debug builds) assert value semantics beyond what
00081  * the compiler can provide.  Since these things are only used in
00082  * RelativeDistinguishedNames, and since RDNs always contain a SET
00083  * of these things, we don't lose anything by hiding the structure
00084  * (and its size).
00085  */
00086 
00087 struct NSSATAVStr {
00088   NSSBER ber;
00089   const NSSOID *oid;
00090   NSSUTF8 *value;
00091   nssStringType stringForm;
00092 };
00093 
00094 /*
00095  * NSSATAV
00096  *
00097  * The public "methods" regarding this "object" are:
00098  *
00099  *  NSSATAV_CreateFromBER   -- constructor
00100  *  NSSATAV_CreateFromUTF8  -- constructor
00101  *  NSSATAV_Create          -- constructor
00102  *
00103  *  NSSATAV_Destroy
00104  *  NSSATAV_GetDEREncoding
00105  *  NSSATAV_GetUTF8Encoding
00106  *  NSSATAV_GetType
00107  *  NSSATAV_GetValue
00108  *  NSSATAV_Compare
00109  *  NSSATAV_Duplicate
00110  *
00111  * The non-public "methods" regarding this "object" are:
00112  *
00113  *  nssATAV_CreateFromBER   -- constructor
00114  *  nssATAV_CreateFromUTF8  -- constructor
00115  *  nssATAV_Create          -- constructor
00116  *
00117  *  nssATAV_Destroy
00118  *  nssATAV_GetDEREncoding
00119  *  nssATAV_GetUTF8Encoding
00120  *  nssATAV_GetType
00121  *  nssATAV_GetValue
00122  *  nssATAV_Compare
00123  *  nssATAV_Duplicate
00124  *
00125  * In debug builds, the following non-public call is also available:
00126  *
00127  *  nssATAV_verifyPointer
00128  */
00129 
00130 /*
00131  * NSSATAV_CreateFromBER
00132  * 
00133  * This routine creates an NSSATAV by decoding a BER- or DER-encoded
00134  * ATAV.  If the optional arena argument is non-null, the memory used 
00135  * will be obtained from that arena; otherwise, the memory will be 
00136  * obtained from the heap.  This routine may return NULL upon error, 
00137  * in which case it will have created an error stack.
00138  *
00139  * The error may be one of the following values:
00140  *  NSS_ERROR_INVALID_BER
00141  *  NSS_ERROR_NO_MEMORY
00142  *
00143  * Return value:
00144  *  NULL upon error
00145  *  A pointer to an NSSATAV upon success
00146  */
00147 
00148 NSS_IMPLEMENT NSSATAV *
00149 NSSATAV_CreateFromBER
00150 (
00151   NSSArena *arenaOpt,
00152   NSSBER *berATAV
00153 )
00154 {
00155   nss_ClearErrorStack();
00156 
00157 #ifdef DEBUG
00158   if( (NSSArena *)NULL != arenaOpt ) {
00159     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
00160       return (NSSATAV *)NULL;
00161     }
00162   }
00163 
00164   /* 
00165    * NSSBERs can be created by the user, 
00166    * so no pointer-tracking can be checked.
00167    */
00168 
00169   if( (NSSBER *)NULL == berATAV ) {
00170     nss_SetError(NSS_ERROR_INVALID_BER);
00171     return (NSSATAV *)NULL;
00172   }
00173 
00174   if( (void *)NULL == berATAV->data ) {
00175     nss_SetError(NSS_ERROR_INVALID_BER);
00176     return (NSSATAV *)NULL;
00177   }
00178 #endif /* DEBUG */
00179 
00180   return nssATAV_CreateFromBER(arenaOpt, berATAV);
00181 }
00182 
00183 /*
00184  * NSSATAV_CreateFromUTF8
00185  *
00186  * This routine creates an NSSATAV by decoding a UTF8 string in the
00187  * "equals" format, e.g., "c=US."  If the optional arena argument is 
00188  * non-null, the memory used will be obtained from that arena; 
00189  * otherwise, the memory will be obtained from the heap.  This routine
00190  * may return NULL upon error, in which case it will have created an
00191  * error stack.
00192  *
00193  * The error may be one of the following values:
00194  *  NSS_ERROR_UNKNOWN_ATTRIBUTE
00195  *  NSS_ERROR_INVALID_STRING
00196  *  NSS_ERROR_NO_MEMORY
00197  *
00198  * Return value:
00199  *  NULL upon error
00200  *  A pointer to an NSSATAV upon success
00201  */
00202 
00203 NSS_IMPLEMENT NSSATAV *
00204 NSSATAV_CreateFromUTF8
00205 (
00206   NSSArena *arenaOpt,
00207   NSSUTF8 *stringATAV
00208 )
00209 {
00210   nss_ClearErrorStack();
00211 
00212 #ifdef DEBUG
00213   if( (NSSArena *)NULL != arenaOpt ) {
00214     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
00215       return (NSSATAV *)NULL;
00216     }
00217   }
00218 
00219   /*
00220    * NSSUTF8s can be created by the user,
00221    * so no pointer-tracking can be checked.
00222    */
00223 
00224   if( (NSSUTF8 *)NULL == stringATAV ) {
00225     nss_SetError(NSS_ERROR_INVALID_UTF8);
00226     return (NSSATAV *)NULL;
00227   }
00228 #endif /* DEBUG */
00229 
00230   return nssATAV_CreateFromUTF8(arenaOpt, stringATAV);
00231 }
00232 
00233 /*
00234  * NSSATAV_Create
00235  *
00236  * This routine creates an NSSATAV from the specified NSSOID and the
00237  * specified data. If the optional arena argument is non-null, the 
00238  * memory used will be obtained from that arena; otherwise, the memory
00239  * will be obtained from the heap.If the specified data length is zero, 
00240  * the data is assumed to be terminated by first zero byte; this allows 
00241  * UTF8 strings to be easily specified.  This routine may return NULL 
00242  * upon error, in which case it will have created an error stack.
00243  *
00244  * The error may be one of the following values:
00245  *  NSS_ERROR_INVALID_ARENA
00246  *  NSS_ERROR_INVALID_NSSOID
00247  *  NSS_ERROR_INVALID_POINTER
00248  *  NSS_ERROR_NO_MEMORY
00249  *
00250  * Return value:
00251  *  NULL upon error
00252  *  A pointer to an NSSATAV upon success
00253  */
00254 
00255 NSS_IMPLEMENT NSSATAV *
00256 NSSATAV_Create
00257 (
00258   NSSArena *arenaOpt,
00259   const NSSOID *oid,
00260   const void *data,
00261   PRUint32 length
00262 )
00263 {
00264   nss_ClearErrorStack();
00265 
00266 #ifdef DEBUG
00267   if( (NSSArena *)NULL != arenaOpt ) {
00268     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
00269       return (NSSATAV *)NULL;
00270     }
00271   }
00272 
00273   if( PR_SUCCESS != nssOID_verifyPointer(oid) ) {
00274     return (NSSATAV *)NULL;
00275   }
00276 
00277   if( (const void *)NULL == data ) {
00278     nss_SetError(NSS_ERROR_INVALID_POINTER);
00279     return (NSSATAV *)NULL;
00280   }
00281 #endif /* DEBUG */
00282 
00283   return nssATAV_Create(arenaOpt, oid, data, length);
00284 }
00285 
00286 /*
00287  * NSSATAV_Destroy
00288  *
00289  * This routine will destroy an ATAV object.  It should eventually be
00290  * called on all ATAVs created without an arena.  While it is not 
00291  * necessary to call it on ATAVs created within an arena, it is not an
00292  * error to do so.  This routine returns a PRStatus value; if
00293  * successful, it will return PR_SUCCESS.  If unsuccessful, it will
00294  * create an error stack and return PR_FAILURE.
00295  *
00296  * The error may be one of the following values:
00297  *  NSS_ERROR_INVALID_ATAV
00298  *  
00299  * Return value:
00300  *  PR_FAILURE upon error
00301  *  PR_SUCCESS upon success
00302  */
00303 
00304 NSS_IMPLEMENT PRStatus
00305 NSSATAV_Destroy
00306 (
00307   NSSATAV *atav
00308 )
00309 {
00310   nss_ClearErrorStack();
00311 
00312 #ifdef DEBUG
00313   if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
00314     return PR_FAILURE;
00315   }
00316 #endif /* DEBUG */
00317 
00318   return nssATAV_Destroy(atav);
00319 }
00320 
00321 /*
00322  * NSSATAV_GetDEREncoding
00323  *
00324  * This routine will DER-encode an ATAV object. If the optional arena
00325  * argument is non-null, the memory used will be obtained from that
00326  * arena; otherwise, the memory will be obtained from the heap.  This
00327  * routine may return null upon error, in which case it will have 
00328  * created an error stack.
00329  *
00330  * The error may be one of the following values:
00331  *  NSS_ERROR_INVALID_ATAV
00332  *  NSS_ERROR_NO_MEMORY
00333  *
00334  * Return value:
00335  *  NULL upon error
00336  *  The DER encoding of this NSSATAV
00337  */
00338 
00339 NSS_IMPLEMENT NSSDER *
00340 NSSATAV_GetDEREncoding
00341 (
00342   NSSATAV *atav,
00343   NSSArena *arenaOpt
00344 )
00345 {
00346   nss_ClearErrorStack();
00347 
00348 #ifdef DEBUG
00349   if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
00350     return (NSSDER *)NULL;
00351   }
00352 
00353   if( (NSSArena *)NULL != arenaOpt ) {
00354     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
00355       return (NSSDER *)NULL;
00356     }
00357   }
00358 #endif /* DEBUG */
00359 
00360   return nssATAV_GetDEREncoding(atav, arenaOpt);
00361 }
00362 
00363 /*
00364  * NSSATAV_GetUTF8Encoding
00365  *
00366  * This routine returns a UTF8 string containing a string 
00367  * representation of the ATAV in "equals" notation (e.g., "o=Acme").  
00368  * If the optional arena argument is non-null, the memory used will be
00369  * obtained from that arena; otherwise, the memory will be obtained 
00370  * from the heap.  This routine may return null upon error, in which 
00371  * case it will have created an error stack.
00372  *
00373  * The error may be one of the following values:
00374  *  NSS_ERROR_INVALID_ATAV
00375  *  NSS_ERROR_NO_MEMORY
00376  *
00377  * Return value:
00378  *  NULL upon error
00379  *  A pointer to a UTF8 string containing the "equals" encoding of the 
00380  *      ATAV
00381  */
00382 
00383 NSS_IMPLEMENT NSSUTF8 *
00384 NSSATAV_GetUTF8Encoding
00385 (
00386   NSSATAV *atav,
00387   NSSArena *arenaOpt
00388 )
00389 {
00390   nss_ClearErrorStack();
00391 
00392 #ifdef DEBUG
00393   if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
00394     return (NSSUTF8 *)NULL;
00395   }
00396 
00397   if( (NSSArena *)NULL != arenaOpt ) {
00398     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
00399       return (NSSUTF8 *)NULL;
00400     }
00401   }
00402 #endif /* DEBUG */
00403 
00404   return nssATAV_GetUTF8Encoding(atav, arenaOpt);
00405 }
00406 
00407 /*
00408  * NSSATAV_GetType
00409  *
00410  * This routine returns the NSSOID corresponding to the attribute type
00411  * in the specified ATAV.  This routine may return NSS_OID_UNKNOWN 
00412  * upon error, in which case it will have created an error stack.
00413  *
00414  * The error may be one of the following values:
00415  *  NSS_ERROR_INVALID_ATAV
00416  *
00417  * Return value:
00418  *  NSS_OID_UNKNOWN upon error
00419  *  An element of enum NSSOIDenum upon success
00420  */
00421 
00422 NSS_IMPLEMENT const NSSOID *
00423 NSSATAV_GetType
00424 (
00425   NSSATAV *atav
00426 )
00427 {
00428   nss_ClearErrorStack();
00429 
00430 #ifdef DEBUG
00431   if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
00432     return (NSSOID *)NULL;
00433   }
00434 #endif /* DEBUG */
00435 
00436   return nssATAV_GetType(atav);
00437 }
00438 
00439 /*
00440  * NSSATAV_GetValue
00441  *
00442  * This routine returns a string containing the attribute value
00443  * in the specified ATAV.  If the optional arena argument is non-null,
00444  * the memory used will be obtained from that arena; otherwise, the
00445  * memory will be obtained from the heap.  This routine may return
00446  * NULL upon error, in which case it will have created an error stack.
00447  *
00448  * The error may be one of the following values:
00449  *  NSS_ERROR_INVALID_ATAV
00450  *  NSS_ERROR_NO_MEMORY
00451  *
00452  * Return value:
00453  *  NULL upon error
00454  *  A pointer to an NSSItem containing the attribute value.
00455  */
00456 
00457 NSS_IMPLEMENT NSSUTF8 *
00458 NSSATAV_GetValue
00459 (
00460   NSSATAV *atav,
00461   NSSArena *arenaOpt
00462 )
00463 {
00464   nss_ClearErrorStack();
00465 
00466 #ifdef DEBUG
00467   if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
00468     return (NSSUTF8 *)NULL;
00469   }
00470 
00471   if( (NSSArena *)NULL != arenaOpt ) {
00472     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
00473       return (NSSUTF8 *)NULL;
00474     }
00475   }
00476 #endif /* DEBUG */
00477 
00478   return nssATAV_GetValue(atav, arenaOpt);
00479 }
00480 
00481 /*
00482  * NSSATAV_Compare
00483  *
00484  * This routine compares two ATAVs for equality.  For two ATAVs to be
00485  * equal, the attribute types must be the same, and the attribute 
00486  * values must have equal length and contents.  The result of the 
00487  * comparison will be stored at the location pointed to by the "equalp"
00488  * variable, which must point to a valid PRBool.  This routine may 
00489  * return PR_FAILURE upon error, in which case it will have created an
00490  * error stack.
00491  *
00492  * The error may be one of the following values:
00493  *  NSS_ERROR_INVALID_ATAV
00494  *  NSS_ERROR_INVALID_ARGUMENT
00495  *
00496  * Return value:
00497  *  PR_FAILURE on error
00498  *  PR_SUCCESS upon a successful comparison (equal or not)
00499  */
00500 
00501 NSS_IMPLEMENT PRStatus
00502 NSSATAV_Compare
00503 (
00504   NSSATAV *atav1,
00505   NSSATAV *atav2,
00506   PRBool *equalp
00507 )
00508 {
00509   nss_ClearErrorStack();
00510 
00511 #ifdef DEBUG
00512   if( PR_SUCCESS != nssATAV_verifyPointer(atav1) ) {
00513     return PR_FAILURE;
00514   }
00515 
00516   if( PR_SUCCESS != nssATAV_verifyPointer(atav2) ) {
00517     return PR_FAILURE;
00518   }
00519 
00520   if( (PRBool *)NULL == equalp ) {
00521     nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
00522     return PR_FAILURE;
00523   }
00524 #endif /* DEBUG */
00525 
00526   return nssATAV_Compare(atav1, atav2, equalp);
00527 }
00528 
00529 /*
00530  * NSSATAV_Duplicate
00531  *
00532  * This routine duplicates the specified ATAV.  If the optional arena 
00533  * argument is non-null, the memory required will be obtained from
00534  * that arena; otherwise, the memory will be obtained from the heap.  
00535  * This routine may return NULL upon error, in which case it will have 
00536  * created an error stack.
00537  *
00538  * The error may be one of the following values:
00539  *  NSS_ERROR_INVALID_ATAV
00540  *  NSS_ERROR_NO_MEMORY
00541  *
00542  * Return value:
00543  *  NULL on error
00544  *  A pointer to a new ATAV
00545  */
00546 
00547 NSS_IMPLEMENT NSSATAV *
00548 NSSATAV_Duplicate
00549 (
00550   NSSATAV *atav,
00551   NSSArena *arenaOpt
00552 )
00553 {
00554   nss_ClearErrorStack();
00555 
00556 #ifdef DEBUG
00557   if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
00558     return (NSSATAV *)NULL;
00559   }
00560 
00561   if( (NSSArena *)NULL != arenaOpt ) {
00562     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
00563       return (NSSATAV *)NULL;
00564     }
00565   }
00566 #endif /* DEBUG */
00567 
00568   return nssATAV_Duplicate(atav, arenaOpt);
00569 }
00570 
00571 /*
00572  * The pointer-tracking code
00573  */
00574 
00575 #ifdef DEBUG
00576 extern const NSSError NSS_ERROR_INTERNAL_ERROR;
00577 
00578 static nssPointerTracker atav_pointer_tracker;
00579 
00580 static PRStatus
00581 atav_add_pointer
00582 (
00583   const NSSATAV *atav
00584 )
00585 {
00586   PRStatus rv;
00587 
00588   rv = nssPointerTracker_initialize(&atav_pointer_tracker);
00589   if( PR_SUCCESS != rv ) {
00590     return rv;
00591   }
00592 
00593   rv = nssPointerTracker_add(&atav_pointer_tracker, atav);
00594   if( PR_SUCCESS != rv ) {
00595     NSSError e = NSS_GetError();
00596     if( NSS_ERROR_NO_MEMORY != e ) {
00597       nss_SetError(NSS_ERROR_INTERNAL_ERROR);
00598     }
00599 
00600     return rv;
00601   }
00602 
00603   return PR_SUCCESS;
00604 }
00605 
00606 static PRStatus
00607 atav_remove_pointer
00608 (
00609   const NSSATAV *atav
00610 )
00611 {
00612   PRStatus rv;
00613 
00614   rv = nssPointerTracker_remove(&atav_pointer_tracker, atav);
00615   if( PR_SUCCESS != rv ) {
00616     nss_SetError(NSS_ERROR_INTERNAL_ERROR);
00617   }
00618 
00619   return rv;
00620 }
00621 
00622 /*
00623  * nssATAV_verifyPointer
00624  *
00625  * This method is only present in debug builds.
00626  *
00627  * If the specified pointer is a valid pointer to an NSSATAV object,
00628  * this routine will return PR_SUCCESS.  Otherwise, it will put an
00629  * error on the error stack and return PR_FAILRUE.
00630  *
00631  * The error may be one of the following values:
00632  *  NSS_ERROR_INVALID_NSSATAV
00633  *  NSS_ERROR_NO_MEMORY
00634  *
00635  * Return value:
00636  *  PR_SUCCESS if the pointer is valid
00637  *  PR_FAILURE if it isn't
00638  */
00639 
00640 NSS_IMPLEMENT PRStatus
00641 nssATAV_verifyPointer
00642 (
00643   NSSATAV *atav
00644 )
00645 {
00646   PRStatus rv;
00647 
00648   rv = nssPointerTracker_initialize(&atav_pointer_tracker);
00649   if( PR_SUCCESS != rv ) {
00650     return PR_FAILURE;
00651   }
00652 
00653   rv = nssPointerTracker_verify(&atav_pointer_tracker, atav);
00654   if( PR_SUCCESS != rv ) {
00655     nss_SetError(NSS_ERROR_INVALID_ATAV);
00656     return PR_FAILURE;
00657   }
00658 
00659   return PR_SUCCESS;
00660 }
00661 #endif /* DEBUG */
00662 
00663 typedef struct {
00664   NSSBER oid;
00665   NSSBER value;
00666 } atav_holder;
00667 
00668 static const nssASN1Template nss_atav_template[] = {
00669   { nssASN1_SEQUENCE, 0, NULL, sizeof(atav_holder) },
00670   { nssASN1_OBJECT_ID, nsslibc_offsetof(atav_holder, oid), NULL, 0 },
00671   { nssASN1_ANY, nsslibc_offsetof(atav_holder, value), NULL, 0 },
00672   { 0, 0, NULL, 0 }
00673 };
00674 
00675 /*
00676  * There are several common attributes, with well-known type aliases
00677  * and value semantics.  This table lists the ones we recognize.
00678  */
00679 
00680 struct nss_attribute_data_str {
00681   const NSSOID **oid;
00682   nssStringType stringType;
00683   PRUint32 minStringLength;
00684   PRUint32 maxStringLength; /* zero for no limit */
00685 };
00686 
00687 static const struct nss_attribute_data_str nss_attribute_data[] = {
00688   { &NSS_OID_X520_NAME,                     
00689     nssStringType_DirectoryString, 1, 32768 },
00690   { &NSS_OID_X520_COMMON_NAME,              
00691     nssStringType_DirectoryString, 1,    64 },
00692   { &NSS_OID_X520_SURNAME,                  
00693     nssStringType_DirectoryString, 1,    40 },
00694   { &NSS_OID_X520_GIVEN_NAME,               
00695     nssStringType_DirectoryString, 1,    16 },
00696   { &NSS_OID_X520_INITIALS,                 
00697     nssStringType_DirectoryString, 1,     5 },
00698   { &NSS_OID_X520_GENERATION_QUALIFIER,     
00699     nssStringType_DirectoryString, 1,     3 },
00700   { &NSS_OID_X520_DN_QUALIFIER,             
00701     nssStringType_PrintableString, 1,     0 },
00702   { &NSS_OID_X520_COUNTRY_NAME,             
00703     nssStringType_PrintableString, 2,     2 },
00704   { &NSS_OID_X520_LOCALITY_NAME,            
00705     nssStringType_DirectoryString, 1,   128 },
00706   { &NSS_OID_X520_STATE_OR_PROVINCE_NAME,   
00707     nssStringType_DirectoryString, 1,   128 },
00708   { &NSS_OID_X520_ORGANIZATION_NAME,        
00709     nssStringType_DirectoryString, 1,    64 },
00710   { &NSS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 
00711     nssStringType_DirectoryString, 1,
00712     /*
00713      * Note, draft #11 defines both "32" and "64" for this maximum,
00714      * in two separate places.  Until it's settled, "conservative
00715      * in what you send."  We're always liberal in what we accept.
00716      */
00717                                          32 },
00718   { &NSS_OID_X520_TITLE,                    
00719     nssStringType_DirectoryString, 1,    64 },
00720   { &NSS_OID_RFC1274_EMAIL,                 
00721     nssStringType_PHGString,       1,   128 }
00722 };
00723 
00724 PRUint32 nss_attribute_data_quantity = 
00725   (sizeof(nss_attribute_data)/sizeof(nss_attribute_data[0]));
00726 
00727 static nssStringType
00728 nss_attr_underlying_string_form
00729 (
00730   nssStringType type,
00731   void *data
00732 )
00733 {
00734   if( nssStringType_DirectoryString == type ) {
00735     PRUint8 tag = *(PRUint8 *)data;
00736     switch( tag & nssASN1_TAGNUM_MASK ) {
00737     case 20:
00738       /*
00739        * XXX fgmr-- we have to accept Latin-1 for Teletex; (see
00740        * below) but is T61 a suitable value for "Latin-1"?
00741        */
00742       return nssStringType_TeletexString;
00743     case 19:
00744       return nssStringType_PrintableString;
00745     case 28:
00746       return nssStringType_UniversalString;
00747     case 30:
00748       return nssStringType_BMPString;
00749     case 12:
00750       return nssStringType_UTF8String;
00751     default:
00752       return nssStringType_Unknown;
00753     }
00754   }
00755 
00756   return type;
00757 }
00758     
00759 
00760 /*
00761  * This routine decodes the attribute value, in a type-specific way.
00762  *
00763  */
00764 
00765 static NSSUTF8 *
00766 nss_attr_to_utf8
00767 (
00768   NSSArena *arenaOpt,
00769   const NSSOID *oid,
00770   NSSItem *item,
00771   nssStringType *stringForm
00772 )
00773 {
00774   NSSUTF8 *rv = (NSSUTF8 *)NULL;
00775   PRUint32 i;
00776   const struct nss_attribute_data_str *which = 
00777     (struct nss_attribute_data_str *)NULL;
00778   PRUint32 len = 0;
00779 
00780   for( i = 0; i < nss_attribute_data_quantity; i++ ) {
00781     if( *(nss_attribute_data[ i ].oid) == oid ) {
00782       which = &nss_attribute_data[i];
00783       break;
00784     }
00785   }
00786 
00787   if( (struct nss_attribute_data_str *)NULL == which ) {
00788     /* Unknown OID.  Encode it as hex. */
00789     PRUint8 *c;
00790     PRUint8 *d = (PRUint8 *)item->data;
00791     PRUint32 amt = item->size;
00792 
00793     if( item->size >= 0x7FFFFFFF ) {
00794       nss_SetError(NSS_ERROR_INVALID_STRING);
00795       return (NSSUTF8 *)NULL;
00796     }
00797 
00798     len = 1 + (item->size * 2) + 1; /* '#' + hex + '\0' */
00799     rv = (NSSUTF8 *)nss_ZAlloc(arenaOpt, len);
00800     if( (NSSUTF8 *)NULL == rv ) {
00801       return (NSSUTF8 *)NULL;
00802     }
00803 
00804     c = (PRUint8 *)rv;
00805     *c++ = '#'; /* XXX fgmr check this */
00806     while( amt > 0 ) {
00807       static char hex[16] = "0123456789ABCDEF";
00808       *c++ = hex[ ((*d) & 0xf0) >> 4 ];
00809       *c++ = hex[ ((*d) & 0x0f)      ];
00810     }
00811 
00812     /* *c = '\0'; nss_ZAlloc, remember */
00813 
00814     *stringForm = nssStringType_Unknown; /* force exact comparison */
00815   } else {
00816     PRStatus status;
00817     rv = nssUTF8_CreateFromBER(arenaOpt, which->stringType, 
00818                                (NSSBER *)item);
00819 
00820     if( (NSSUTF8 *)NULL == rv ) {
00821       return (NSSUTF8 *)NULL;
00822     }
00823 
00824     len = nssUTF8_Length(rv, &status);
00825     if( PR_SUCCESS != status || len == 0 ) {
00826       nss_ZFreeIf(rv);
00827       return (NSSUTF8 *)NULL;
00828     }
00829 
00830     *stringForm = nss_attr_underlying_string_form(which->stringType,
00831                                                   item->data);
00832   }
00833 
00834   return rv;
00835 }
00836 
00837 /*
00838  * nssATAV_CreateFromBER
00839  * 
00840  * This routine creates an NSSATAV by decoding a BER- or DER-encoded
00841  * ATAV.  If the optional arena argument is non-null, the memory used 
00842  * will be obtained from that arena; otherwise, the memory will be 
00843  * obtained from the heap.  This routine may return NULL upon error, 
00844  * in which case it will have set an error on the error stack.
00845  *
00846  * The error may be one of the following values:
00847  *  NSS_ERROR_INVALID_BER
00848  *  NSS_ERROR_NO_MEMORY
00849  *
00850  * Return value:
00851  *  NULL upon error
00852  *  A pointer to an NSSATAV upon success
00853  */
00854 
00855 NSS_IMPLEMENT NSSATAV *
00856 nssATAV_CreateFromBER
00857 (
00858   NSSArena *arenaOpt,
00859   const NSSBER *berATAV
00860 )
00861 {
00862   atav_holder holder;
00863   PRStatus status;
00864   NSSATAV *rv;
00865 
00866 #ifdef NSSDEBUG
00867   if( (NSSArena *)NULL != arenaOpt ) {
00868     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
00869       return (NSSATAV *)NULL;
00870     }
00871   }
00872 
00873   /* 
00874    * NSSBERs can be created by the user, 
00875    * so no pointer-tracking can be checked.
00876    */
00877 
00878   if( (NSSBER *)NULL == berATAV ) {
00879     nss_SetError(NSS_ERROR_INVALID_BER);
00880     return (NSSATAV *)NULL;
00881   }
00882 
00883   if( (void *)NULL == berATAV->data ) {
00884     nss_SetError(NSS_ERROR_INVALID_BER);
00885     return (NSSATAV *)NULL;
00886   }
00887 #endif /* NSSDEBUG */
00888 
00889   status = nssASN1_DecodeBER(arenaOpt, &holder, 
00890                              nss_atav_template, berATAV);
00891   if( PR_SUCCESS != status ) {
00892     return (NSSATAV *)NULL;
00893   }
00894 
00895   rv = nss_ZNEW(arenaOpt, NSSATAV);
00896   if( (NSSATAV *)NULL == rv ) {
00897     nss_ZFreeIf(holder.oid.data);
00898     nss_ZFreeIf(holder.value.data);
00899     return (NSSATAV *)NULL;
00900   }
00901 
00902   rv->oid = nssOID_CreateFromBER(&holder.oid);
00903   if( (NSSOID *)NULL == rv->oid ) {
00904     nss_ZFreeIf(rv);
00905     nss_ZFreeIf(holder.oid.data);
00906     nss_ZFreeIf(holder.value.data);
00907     return (NSSATAV *)NULL;
00908   }
00909 
00910   nss_ZFreeIf(holder.oid.data);
00911 
00912   rv->ber.data = nss_ZAlloc(arenaOpt, berATAV->size);
00913   if( (void *)NULL == rv->ber.data ) {
00914     nss_ZFreeIf(rv);
00915     nss_ZFreeIf(holder.value.data);
00916     return (NSSATAV *)NULL;
00917   }
00918 
00919   rv->ber.size = berATAV->size;
00920   (void)nsslibc_memcpy(rv->ber.data, berATAV->data, berATAV->size);
00921 
00922   rv->value = nss_attr_to_utf8(arenaOpt, rv->oid, &holder.value,
00923                                &rv->stringForm);
00924   if( (NSSUTF8 *)NULL == rv->value ) {
00925     nss_ZFreeIf(rv->ber.data);
00926     nss_ZFreeIf(rv);
00927     nss_ZFreeIf(holder.value.data);
00928     return (NSSATAV *)NULL;
00929   }
00930 
00931   nss_ZFreeIf(holder.value.data);
00932 
00933 #ifdef DEBUG
00934   if( PR_SUCCESS != atav_add_pointer(rv) ) {
00935     nss_ZFreeIf(rv->ber.data);
00936     nss_ZFreeIf(rv->value);
00937     nss_ZFreeIf(rv);
00938     return (NSSATAV *)NULL;
00939   }
00940 #endif /* DEBUG */
00941 
00942   return rv;
00943 }
00944 
00945 static PRBool
00946 nss_atav_utf8_string_is_hex
00947 (
00948   const NSSUTF8 *s
00949 )
00950 {
00951   /* All hex digits are ASCII, so this works */
00952   PRUint8 *p = (PRUint8 *)s;
00953 
00954   for( ; (PRUint8)0 != *p; p++ ) {
00955     if( (('0' <= *p) && (*p <= '9')) ||
00956         (('A' <= *p) && (*p <= 'F')) ||
00957         (('a' <= *p) && (*p <= 'f')) ) {
00958       continue;
00959     } else {
00960       return PR_FALSE;
00961     }
00962   }
00963 
00964   return PR_TRUE;
00965 }
00966 
00967 static NSSUTF8
00968 nss_atav_fromhex
00969 (
00970   NSSUTF8 *d
00971 )
00972 {
00973   NSSUTF8 rv;
00974 
00975   if( d[0] <= '9' ) {
00976     rv = (d[0] - '0') * 16;
00977   } else if( d[0] >= 'a' ) {
00978     rv = (d[0] - 'a' + 10) * 16;
00979   } else {
00980     rv = (d[0] - 'A' + 10);
00981   }
00982 
00983   if( d[1] <= '9' ) {
00984     rv += (d[1] - '0');
00985   } else if( d[1] >= 'a' ) {
00986     rv += (d[1] - 'a' + 10);
00987   } else {
00988     rv += (d[1] - 'A' + 10);
00989   }
00990 
00991   return rv;
00992 }
00993 
00994 /*
00995  * nssATAV_CreateFromUTF8
00996  *
00997  * This routine creates an NSSATAV by decoding a UTF8 string in the
00998  * "equals" format, e.g., "c=US."  If the optional arena argument is 
00999  * non-null, the memory used will be obtained from that arena; 
01000  * otherwise, the memory will be obtained from the heap.  This routine
01001  * may return NULL upon error, in which case it will have set an error 
01002  * on the error stack.
01003  *
01004  * The error may be one of the following values:
01005  *  NSS_ERROR_UNKNOWN_ATTRIBUTE
01006  *  NSS_ERROR_INVALID_STRING
01007  *  NSS_ERROR_NO_MEMORY
01008  *
01009  * Return value:
01010  *  NULL upon error
01011  *  A pointer to an NSSATAV upon success
01012  */
01013 
01014 extern const NSSError NSS_ERROR_INTERNAL_ERROR;
01015 
01016 NSS_IMPLEMENT NSSATAV *
01017 nssATAV_CreateFromUTF8
01018 (
01019   NSSArena *arenaOpt,
01020   const NSSUTF8 *stringATAV
01021 )
01022 {
01023   char *c;
01024   NSSUTF8 *type;
01025   NSSUTF8 *value;
01026   PRUint32 i;
01027   const NSSOID *oid = (NSSOID *)NULL;
01028   NSSATAV *rv;
01029   NSSItem xitem;
01030 
01031   xitem.data = (void *)NULL;
01032 
01033   for( c = (char *)stringATAV; '\0' != *c; c++ ) {
01034     if( '=' == *c ) {
01035 #ifdef PEDANTIC
01036       /*
01037        * Theoretically, one could have an '=' in an 
01038        * attribute string alias.  We don't, yet, though.
01039        */
01040       if( (char *)stringATAV == c ) {
01041         nss_SetError(NSS_ERROR_INVALID_STRING);
01042         return (NSSATAV *)NULL;
01043       } else {
01044         if( '\\' == c[-1] ) {
01045           continue;
01046         }
01047       }
01048 #endif /* PEDANTIC */
01049       break;
01050     }
01051   }
01052 
01053   if( '\0' == *c ) {
01054     nss_SetError(NSS_ERROR_INVALID_UTF8);
01055     return (NSSATAV *)NULL;
01056   } else {
01057     c++;
01058     value = (NSSUTF8 *)c;
01059   }
01060 
01061   i = ((NSSUTF8 *)c - stringATAV);
01062   type = (NSSUTF8 *)nss_ZAlloc((NSSArena *)NULL, i);
01063   if( (NSSUTF8 *)NULL == type ) {
01064     return (NSSATAV *)NULL;
01065   }
01066 
01067   (void)nsslibc_memcpy(type, stringATAV, i-1);
01068 
01069   c = (char *)stringATAV;
01070   if( (('0' <= *c) && (*c <= '9')) || ('#' == *c) ) {
01071     oid = nssOID_CreateFromUTF8(type);
01072     if( (NSSOID *)NULL == oid ) {
01073       nss_ZFreeIf(type);
01074       return (NSSATAV *)NULL;
01075     }
01076   } else {
01077     for( i = 0; i < nss_attribute_type_alias_count; i++ ) {
01078       PRStatus status;
01079       const nssAttributeTypeAliasTable *e = &nss_attribute_type_aliases[i];
01080       PRBool match = nssUTF8_CaseIgnoreMatch(type, e->alias, &status);
01081       if( PR_SUCCESS != status ) {
01082         nss_ZFreeIf(type);
01083         return (NSSATAV *)NULL;
01084       }
01085       if( PR_TRUE == match ) {
01086         oid = *(e->oid);
01087         break;
01088       }
01089     }
01090 
01091     if( (NSSOID *)NULL == oid ) {
01092       nss_ZFreeIf(type);
01093       nss_SetError(NSS_ERROR_UNKNOWN_ATTRIBUTE);
01094       return (NSSATAV *)NULL;
01095     }
01096   }
01097 
01098   nss_ZFreeIf(type);
01099   type = (NSSUTF8 *)NULL;
01100 
01101   rv = nss_ZNEW(arenaOpt, NSSATAV);
01102   if( (NSSATAV *)NULL == rv ) {
01103     return (NSSATAV *)NULL;
01104   }
01105 
01106   rv->oid = oid;
01107 
01108   if( '#' == *value ) { /* XXX fgmr.. was it '#'?  or backslash? */
01109     PRUint32 size;
01110     PRUint32 len;
01111     NSSUTF8 *c;
01112     NSSUTF8 *d;
01113     PRStatus status;
01114     /* It's in hex */
01115 
01116     value++;
01117     if( PR_TRUE != nss_atav_utf8_string_is_hex(value) ) {
01118       (void)nss_ZFreeIf(rv);
01119       nss_SetError(NSS_ERROR_INVALID_STRING);
01120       return (NSSATAV *)NULL;
01121     }
01122 
01123     size = nssUTF8_Size(value, &status);
01124     if( PR_SUCCESS != status ) {
01125       /* 
01126        * Only returns an error on bad pointer (nope) or string
01127        * too long.  The defined limits for known attributes are
01128        * small enough to fit in PRUint32, and when undefined we
01129        * get to apply our own practical limits.  Ergo, I say the 
01130        * string is invalid.
01131        */
01132       (void)nss_ZFreeIf(rv);
01133       nss_SetError(NSS_ERROR_INVALID_STRING);
01134       return (NSSATAV *)NULL;
01135     }
01136 
01137     if( ((size-1) & 1) ) {
01138       /* odd length */
01139       (void)nss_ZFreeIf(rv);
01140       nss_SetError(NSS_ERROR_INVALID_STRING);
01141       return (NSSATAV *)NULL;
01142     }
01143 
01144     len = (size-1)/2;
01145 
01146     rv->value = (NSSUTF8 *)nss_ZAlloc(arenaOpt, len+1);
01147     if( (NSSUTF8 *)NULL == rv->value ) {
01148       (void)nss_ZFreeIf(rv);
01149       return (NSSATAV *)NULL;
01150     }
01151 
01152     xitem.size = len;
01153     xitem.data = (void *)rv->value;
01154 
01155     for( c = rv->value, d = value; len--; c++, d += 2 ) {
01156       *c = nss_atav_fromhex(d);
01157     }
01158 
01159     *c = 0;
01160   } else {
01161     PRStatus status;
01162     PRUint32 i, len;
01163     PRUint8 *s;
01164 
01165     /*
01166      * XXX fgmr-- okay, this is a little wasteful, and should
01167      * probably be abstracted out a bit.  Later.
01168      */
01169 
01170     rv->value = nssUTF8_Duplicate(value, arenaOpt);
01171     if( (NSSUTF8 *)NULL == rv->value ) {
01172       (void)nss_ZFreeIf(rv);
01173       return (NSSATAV *)NULL;
01174     }
01175 
01176     len = nssUTF8_Size(rv->value, &status);
01177     if( PR_SUCCESS != status ) {
01178       (void)nss_ZFreeIf(rv->value);
01179       (void)nss_ZFreeIf(rv);
01180       return (NSSATAV *)NULL;
01181     }
01182 
01183     s = (PRUint8 *)rv->value;
01184     for( i = 0; i < len; i++ ) {
01185       if( '\\' == s[i] ) {
01186         (void)nsslibc_memcpy(&s[i], &s[i+1], len-i-1);
01187       }
01188     }
01189   }
01190 
01191   /* Now just BER-encode the baby and we're through.. */
01192   {
01193     const struct nss_attribute_data_str *which = 
01194       (struct nss_attribute_data_str *)NULL;
01195     PRUint32 i;
01196     NSSArena *a;
01197     NSSDER *oidder;
01198     NSSItem *vitem;
01199     atav_holder ah;
01200     NSSDER *status;
01201 
01202     for( i = 0; i < nss_attribute_data_quantity; i++ ) {
01203       if( *(nss_attribute_data[ i ].oid) == rv->oid ) {
01204         which = &nss_attribute_data[i];
01205         break;
01206       }
01207     }
01208 
01209     a = NSSArena_Create();
01210     if( (NSSArena *)NULL == a ) {
01211       (void)nss_ZFreeIf(rv->value);
01212       (void)nss_ZFreeIf(rv);
01213       return (NSSATAV *)NULL;
01214     }
01215 
01216     oidder = nssOID_GetDEREncoding(rv->oid, (NSSDER *)NULL, a);
01217     if( (NSSDER *)NULL == oidder ) {
01218       (void)NSSArena_Destroy(a);
01219       (void)nss_ZFreeIf(rv->value);
01220       (void)nss_ZFreeIf(rv);
01221       return (NSSATAV *)NULL;
01222     }
01223 
01224     if( (struct nss_attribute_data_str *)NULL == which ) {
01225       /*
01226        * We'll just have to take the user data as an octet stream.
01227        */
01228       if( (void *)NULL == xitem.data ) {
01229         /*
01230          * This means that an ATTR entry has been added to oids.txt,
01231          * but no corresponding entry has been added to the array
01232          * ns_attribute_data[] above.
01233          */
01234         nss_SetError(NSS_ERROR_INTERNAL_ERROR);
01235         (void)NSSArena_Destroy(a);
01236         (void)nss_ZFreeIf(rv->value);
01237         (void)nss_ZFreeIf(rv);
01238         return (NSSATAV *)NULL;
01239       }
01240 
01241       vitem = nssASN1_EncodeItem(a, (NSSDER *)NULL, &xitem, 
01242                                  nssASN1Template_OctetString, NSSASN1DER);
01243       if( (NSSItem *)NULL == vitem ) {
01244         (void)NSSArena_Destroy(a);
01245         (void)nss_ZFreeIf(rv->value);
01246         (void)nss_ZFreeIf(rv);
01247         return (NSSATAV *)NULL;
01248       }
01249 
01250       rv->stringForm = nssStringType_Unknown;
01251     } else {
01252       PRUint32 length = 0;
01253       PRStatus stat;
01254       
01255       length = nssUTF8_Length(rv->value, &stat);
01256       if( PR_SUCCESS != stat ) {
01257         (void)NSSArena_Destroy(a);
01258         (void)nss_ZFreeIf(rv->value);
01259         (void)nss_ZFreeIf(rv);
01260         return (NSSATAV *)NULL;
01261       }
01262 
01263       if( ((0 != which->minStringLength) && 
01264            (length < which->minStringLength)) ||
01265           ((0 != which->maxStringLength) &&
01266            (length > which->maxStringLength)) ) {
01267         nss_SetError(NSS_ERROR_INVALID_STRING);
01268         (void)NSSArena_Destroy(a);
01269         (void)nss_ZFreeIf(rv->value);
01270         (void)nss_ZFreeIf(rv);
01271         return (NSSATAV *)NULL;
01272       }
01273 
01274       vitem = nssUTF8_GetDEREncoding(a, which->stringType, rv->value);
01275       if( (NSSItem *)NULL == vitem ) {
01276         (void)NSSArena_Destroy(a);
01277         (void)nss_ZFreeIf(rv->value);
01278         (void)nss_ZFreeIf(rv);
01279         return (NSSATAV *)NULL;
01280       }
01281 
01282       if( nssStringType_DirectoryString == which->stringType ) {
01283         rv->stringForm = nssStringType_UTF8String;
01284       } else {
01285         rv->stringForm = which->stringType;
01286       }
01287     }
01288 
01289     ah.oid = *oidder;
01290     ah.value = *vitem;
01291 
01292     status = nssASN1_EncodeItem(arenaOpt, &rv->ber, &ah, 
01293                                 nss_atav_template, NSSASN1DER);
01294 
01295     if( (NSSDER *)NULL == status ) {
01296       (void)NSSArena_Destroy(a);
01297       (void)nss_ZFreeIf(rv->value);
01298       (void)nss_ZFreeIf(rv);
01299       return (NSSATAV *)NULL;
01300     }
01301 
01302     (void)NSSArena_Destroy(a);
01303   }
01304 
01305   return rv;
01306 }
01307 
01308 /*
01309  * nssATAV_Create
01310  *
01311  * This routine creates an NSSATAV from the specified NSSOID and the
01312  * specified data. If the optional arena argument is non-null, the 
01313  * memory used will be obtained from that arena; otherwise, the memory
01314  * will be obtained from the heap.If the specified data length is zero, 
01315  * the data is assumed to be terminated by first zero byte; this allows 
01316  * UTF8 strings to be easily specified.  This routine may return NULL 
01317  * upon error, in which case it will have set an error on the error 
01318  * stack.
01319  *
01320  * The error may be one of the following values:
01321  *  NSS_ERROR_INVALID_ARENA
01322  *  NSS_ERROR_INVALID_NSSOID
01323  *  NSS_ERROR_INVALID_POINTER
01324  *  NSS_ERROR_NO_MEMORY
01325  *
01326  * Return value:
01327  *  NULL upon error
01328  *  A pointer to an NSSATAV upon success
01329  */
01330 
01331 NSS_IMPLEMENT NSSATAV *
01332 nssATAV_Create
01333 (
01334   NSSArena *arenaOpt,
01335   const NSSOID *oid,
01336   const void *data,
01337   PRUint32 length
01338 )
01339 {
01340 #ifdef NSSDEBUG
01341   if( (NSSArena *)NULL != arenaOpt ) {
01342     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
01343       return (NSSATAV *)NULL;
01344     }
01345   }
01346 
01347   if( PR_SUCCESS != nssOID_verifyPointer(oid) ) {
01348     return (NSSATAV *)NULL;
01349   }
01350 
01351   if( (const void *)NULL == data ) {
01352     nss_SetError(NSS_ERROR_INVALID_POINTER);
01353     return (NSSATAV *)NULL;
01354   }
01355 #endif /* NSSDEBUG */
01356 
01357   /* XXX fgmr-- oops, forgot this one */
01358   return (NSSATAV *)NULL;
01359 }
01360 
01361 /*
01362  * nssATAV_Destroy
01363  *
01364  * This routine will destroy an ATAV object.  It should eventually be
01365  * called on all ATAVs created without an arena.  While it is not 
01366  * necessary to call it on ATAVs created within an arena, it is not an
01367  * error to do so.  This routine returns a PRStatus value; if
01368  * successful, it will return PR_SUCCESS.  If unsuccessful, it will
01369  * set an error on the error stack and return PR_FAILURE.
01370  *
01371  * The error may be one of the following values:
01372  *  NSS_ERROR_INVALID_ATAV
01373  *  
01374  * Return value:
01375  *  PR_FAILURE upon error
01376  *  PR_SUCCESS upon success
01377  */
01378 
01379 NSS_IMPLEMENT PRStatus
01380 nssATAV_Destroy
01381 (
01382   NSSATAV *atav
01383 )
01384 {
01385 #ifdef NSSDEBUG
01386   if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
01387     return PR_FAILURE;
01388   }
01389 #endif /* NSSDEBUG */
01390 
01391   (void)nss_ZFreeIf(atav->ber.data);
01392   (void)nss_ZFreeIf(atav->value);
01393 
01394 #ifdef DEBUG
01395   if( PR_SUCCESS != atav_remove_pointer(atav) ) {
01396     return PR_FAILURE;
01397   }
01398 #endif /* DEBUG */
01399 
01400   return PR_SUCCESS;
01401 }
01402 
01403 /*
01404  * nssATAV_GetDEREncoding
01405  *
01406  * This routine will DER-encode an ATAV object. If the optional arena
01407  * argument is non-null, the memory used will be obtained from that
01408  * arena; otherwise, the memory will be obtained from the heap.  This
01409  * routine may return null upon error, in which case it will have set
01410  * an error on the error stack.
01411  *
01412  * The error may be one of the following values:
01413  *  NSS_ERROR_INVALID_ATAV
01414  *  NSS_ERROR_NO_MEMORY
01415  *
01416  * Return value:
01417  *  NULL upon error
01418  *  The DER encoding of this NSSATAV
01419  */
01420 
01421 NSS_IMPLEMENT NSSDER *
01422 nssATAV_GetDEREncoding
01423 (
01424   NSSATAV *atav,
01425   NSSArena *arenaOpt
01426 )
01427 {
01428   NSSDER *rv;
01429 
01430 #ifdef NSSDEBUG
01431   if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
01432     return (NSSDER *)NULL;
01433   }
01434 #endif /* NSSDEBUG */
01435 
01436   rv = nss_ZNEW(arenaOpt, NSSDER);
01437   if( (NSSDER *)NULL == rv ) {
01438     return (NSSDER *)NULL;
01439   }
01440 
01441   rv->data = nss_ZAlloc(arenaOpt, atav->ber.size);
01442   if( (void *)NULL == rv->data ) {
01443     (void)nss_ZFreeIf(rv);
01444     return (NSSDER *)NULL;
01445   }
01446 
01447   rv->size = atav->ber.size;
01448   if( NULL == nsslibc_memcpy(rv->data, atav->ber.data, rv->size) ) {
01449     (void)nss_ZFreeIf(rv->data);
01450     (void)nss_ZFreeIf(rv);
01451     return (NSSDER *)NULL;
01452   }
01453 
01454   return rv;
01455 }
01456 
01457 /*
01458  * nssATAV_GetUTF8Encoding
01459  *
01460  * This routine returns a UTF8 string containing a string 
01461  * representation of the ATAV in "equals" notation (e.g., "o=Acme").  
01462  * If the optional arena argument is non-null, the memory used will be
01463  * obtained from that arena; otherwise, the memory will be obtained 
01464  * from the heap.  This routine may return null upon error, in which 
01465  * case it will have set an error on the error stack.
01466  *
01467  * The error may be one of the following values:
01468  *  NSS_ERROR_INVALID_ATAV
01469  *  NSS_ERROR_NO_MEMORY
01470  *
01471  * Return value:
01472  *  NULL upon error
01473  *  A pointer to a UTF8 string containing the "equals" encoding of the 
01474  *      ATAV
01475  */
01476 
01477 NSS_IMPLEMENT NSSUTF8 *
01478 nssATAV_GetUTF8Encoding
01479 (
01480   NSSATAV *atav,
01481   NSSArena *arenaOpt
01482 )
01483 {
01484   NSSUTF8 *rv;
01485   PRUint32 i;
01486   const NSSUTF8 *alias = (NSSUTF8 *)NULL;
01487   NSSUTF8 *oid;
01488   NSSUTF8 *value;
01489   PRUint32 oidlen;
01490   PRUint32 valuelen;
01491   PRUint32 totallen;
01492   PRStatus status;
01493 
01494 #ifdef NSSDEBUG
01495   if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
01496     return (NSSUTF8 *)NULL;
01497   }
01498 #endif /* NSSDEBUG */
01499 
01500   for( i = 0; i < nss_attribute_type_alias_count; i++ ) {
01501     if( *(nss_attribute_type_aliases[i].oid) == atav->oid ) {
01502       alias = nss_attribute_type_aliases[i].alias;
01503       break;
01504     }
01505   }
01506 
01507   if( (NSSUTF8 *)NULL == alias ) {
01508     oid = nssOID_GetUTF8Encoding(atav->oid, (NSSArena *)NULL);
01509     if( (NSSUTF8 *)NULL == oid ) {
01510       return (NSSUTF8 *)NULL;
01511     }
01512 
01513     oidlen = nssUTF8_Size(oid, &status);
01514     if( PR_SUCCESS != status ) {
01515       (void)nss_ZFreeIf(oid);
01516       return (NSSUTF8 *)NULL;
01517     }
01518   } else {
01519     oidlen = nssUTF8_Size(alias, &status);
01520     if( PR_SUCCESS != status ) {
01521       return (NSSUTF8 *)NULL;
01522     }
01523     oid = (NSSUTF8 *)NULL;
01524   }
01525 
01526   value = nssATAV_GetValue(atav, (NSSArena *)NULL);
01527   if( (NSSUTF8 *)NULL == value ) {
01528     (void)nss_ZFreeIf(oid);
01529     return (NSSUTF8 *)NULL;
01530   }
01531 
01532   valuelen = nssUTF8_Size(value, &status);
01533   if( PR_SUCCESS != status ) {
01534     (void)nss_ZFreeIf(value);
01535     (void)nss_ZFreeIf(oid);
01536     return (NSSUTF8 *)NULL;
01537   }
01538 
01539   totallen = oidlen + valuelen - 1 + 1;
01540   rv = (NSSUTF8 *)nss_ZAlloc(arenaOpt, totallen);
01541   if( (NSSUTF8 *)NULL == rv ) {
01542     (void)nss_ZFreeIf(value);
01543     (void)nss_ZFreeIf(oid);
01544     return (NSSUTF8 *)NULL;
01545   }
01546 
01547   if( (NSSUTF8 *)NULL == alias ) {
01548     if( (void *)NULL == nsslibc_memcpy(rv, oid, oidlen-1) ) {
01549       (void)nss_ZFreeIf(rv);
01550       (void)nss_ZFreeIf(value);
01551       (void)nss_ZFreeIf(oid);
01552       return (NSSUTF8 *)NULL;
01553     }
01554   } else {
01555     if( (void *)NULL == nsslibc_memcpy(rv, alias, oidlen-1) ) {
01556       (void)nss_ZFreeIf(rv);
01557       (void)nss_ZFreeIf(value);
01558       return (NSSUTF8 *)NULL;
01559     }
01560   }
01561 
01562   rv[ oidlen-1 ] = '=';
01563 
01564   if( (void *)NULL == nsslibc_memcpy(&rv[oidlen], value, valuelen) ) {
01565     (void)nss_ZFreeIf(rv);
01566     (void)nss_ZFreeIf(value);
01567     (void)nss_ZFreeIf(oid);
01568     return (NSSUTF8 *)NULL;
01569   }
01570 
01571   return rv;
01572 }
01573 
01574 /*
01575  * nssATAV_GetType
01576  *
01577  * This routine returns the NSSOID corresponding to the attribute type
01578  * in the specified ATAV.  This routine may return NSS_OID_UNKNOWN 
01579  * upon error, in which case it will have set an error on the error
01580  * stack.
01581  *
01582  * The error may be one of the following values:
01583  *  NSS_ERROR_INVALID_ATAV
01584  *
01585  * Return value:
01586  *  NSS_OID_UNKNOWN upon error
01587  *  A valid NSSOID pointer upon success
01588  */
01589 
01590 NSS_IMPLEMENT const NSSOID *
01591 nssATAV_GetType
01592 (
01593   NSSATAV *atav
01594 )
01595 {
01596 #ifdef NSSDEBUG
01597   if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
01598     return (NSSOID *)NULL;
01599   }
01600 #endif /* NSSDEBUG */
01601 
01602   return atav->oid;
01603 }
01604 
01605 /*
01606  * nssATAV_GetValue
01607  *
01608  * This routine returns a NSSUTF8 string containing the attribute value
01609  * in the specified ATAV.  If the optional arena argument is non-null,
01610  * the memory used will be obtained from that arena; otherwise, the
01611  * memory will be obtained from the heap.  This routine may return
01612  * NULL upon error, in which case it will have set an error upon the
01613  * error stack.
01614  *
01615  * The error may be one of the following values:
01616  *  NSS_ERROR_INVALID_ATAV
01617  *  NSS_ERROR_NO_MEMORY
01618  *
01619  * Return value:
01620  *  NULL upon error
01621  *  A pointer to an NSSItem containing the attribute value.
01622  */
01623 
01624 NSS_IMPLEMENT NSSUTF8 *
01625 nssATAV_GetValue
01626 (
01627   NSSATAV *atav,
01628   NSSArena *arenaOpt
01629 )
01630 {
01631 #ifdef NSSDEBUG
01632   if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
01633     return (NSSUTF8 *)NULL;
01634   }
01635 #endif /* NSSDEBUG */
01636 
01637   return nssUTF8_Duplicate(atav->value, arenaOpt);
01638 }
01639 
01640 /*
01641  * nssATAV_Compare
01642  *
01643  * This routine compares two ATAVs for equality.  For two ATAVs to be
01644  * equal, the attribute types must be the same, and the attribute 
01645  * values must have equal length and contents.  The result of the 
01646  * comparison will be stored at the location pointed to by the "equalp"
01647  * variable, which must point to a valid PRBool.  This routine may 
01648  * return PR_FAILURE upon error, in which case it will have set an 
01649  * error on the error stack.
01650  *
01651  * The error may be one of the following values:
01652  *  NSS_ERROR_INVALID_ATAV
01653  *  NSS_ERROR_INVALID_ARGUMENT
01654  *
01655  * Return value:
01656  *  PR_FAILURE on error
01657  *  PR_SUCCESS upon a successful comparison (equal or not)
01658  */
01659 
01660 NSS_IMPLEMENT PRStatus
01661 nssATAV_Compare
01662 (
01663   NSSATAV *atav1,
01664   NSSATAV *atav2,
01665   PRBool *equalp
01666 )
01667 {
01668   nssStringType comparison;
01669   PRUint32 len1;
01670   PRUint32 len2;
01671   PRStatus status;
01672 
01673 #ifdef DEBUG
01674   if( PR_SUCCESS != nssATAV_verifyPointer(atav1) ) {
01675     return PR_FAILURE;
01676   }
01677 
01678   if( PR_SUCCESS != nssATAV_verifyPointer(atav2) ) {
01679     return PR_FAILURE;
01680   }
01681 
01682   if( (PRBool *)NULL == equalp ) {
01683     nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
01684     return PR_FAILURE;
01685   }
01686 #endif /* DEBUG */
01687 
01688   if( atav1->oid != atav2->oid ) {
01689     *equalp = PR_FALSE;
01690     return PR_SUCCESS;
01691   }
01692 
01693   if( atav1->stringForm != atav2->stringForm ) {
01694     if( (nssStringType_PrintableString == atav1->stringForm) ||
01695         (nssStringType_PrintableString == atav2->stringForm) ) {
01696       comparison = nssStringType_PrintableString;
01697     } else if( (nssStringType_PHGString == atav1->stringForm) ||
01698                (nssStringType_PHGString == atav2->stringForm) ) {
01699       comparison = nssStringType_PHGString;
01700     } else {
01701       comparison = atav1->stringForm;
01702     }
01703   } else {
01704     comparison = atav1->stringForm;
01705   }
01706 
01707   switch( comparison ) {
01708   case nssStringType_DirectoryString:
01709     nss_SetError(NSS_ERROR_INTERNAL_ERROR);
01710     return PR_FAILURE;
01711   case nssStringType_TeletexString:
01712     break;
01713   case nssStringType_PrintableString:
01714     *equalp = nssUTF8_PrintableMatch(atav1->value, atav2->value, &status);
01715     return status;
01716     /* Case-insensitive, with whitespace reduction */
01717     break;
01718   case nssStringType_UniversalString:
01719     break;
01720   case nssStringType_BMPString:
01721     break;
01722   case nssStringType_GeneralString:
01723     /* what to do here? */
01724     break;
01725   case nssStringType_UTF8String:
01726     break;
01727   case nssStringType_PHGString:
01728     /* Case-insensitive (XXX fgmr, actually see draft-11 pg. 21) */
01729     *equalp = nssUTF8_CaseIgnoreMatch(atav1->value, atav2->value, &status);
01730     return status;
01731   case nssStringType_Unknown:
01732     break;
01733   }
01734   
01735   len1 = nssUTF8_Size(atav1->value, &status);
01736   if( PR_SUCCESS != status ) {
01737     return PR_FAILURE;
01738   }
01739 
01740   len2 = nssUTF8_Size(atav2->value, &status);
01741   if( PR_SUCCESS != status ) {
01742     return PR_FAILURE;
01743   }
01744 
01745   if( len1 != len2 ) {
01746     *equalp = PR_FALSE;
01747     return PR_SUCCESS;
01748   }
01749 
01750   *equalp = nsslibc_memequal(atav1->value, atav2->value, len1, &status);
01751   return status;
01752 }
01753 
01754 
01755 /*
01756  * nssATAV_Duplicate
01757  *
01758  * This routine duplicates the specified ATAV.  If the optional arena 
01759  * argument is non-null, the memory required will be obtained from
01760  * that arena; otherwise, the memory will be obtained from the heap.  
01761  * This routine may return NULL upon error, in which case it will have 
01762  * placed an error on the error stack.
01763  *
01764  * The error may be one of the following values:
01765  *  NSS_ERROR_INVALID_ATAV
01766  *  NSS_ERROR_NO_MEMORY
01767  *
01768  * Return value:
01769  *  NULL on error
01770  *  A pointer to a new ATAV
01771  */
01772 
01773 NSS_IMPLEMENT NSSATAV *
01774 nssATAV_Duplicate
01775 (
01776   NSSATAV *atav,
01777   NSSArena *arenaOpt
01778 )
01779 {
01780   NSSATAV *rv;
01781 
01782 #ifdef NSSDEBUG
01783   if( PR_SUCCESS != nssATAV_verifyPointer(atav) ) {
01784     return (NSSATAV *)NULL;
01785   }
01786 
01787   if( (NSSArena *)NULL != arenaOpt ) {
01788     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
01789       return (NSSATAV *)NULL;
01790     }
01791   }
01792 #endif /* NSSDEBUG */
01793 
01794   rv = nss_ZNEW(arenaOpt, NSSATAV);
01795   if( (NSSATAV *)NULL == rv ) {
01796     return (NSSATAV *)NULL;
01797   }
01798 
01799   rv->oid = atav->oid;
01800   rv->stringForm = atav->stringForm;
01801   rv->value = nssUTF8_Duplicate(atav->value, arenaOpt);
01802   if( (NSSUTF8 *)NULL == rv->value ) {
01803     (void)nss_ZFreeIf(rv);
01804     return (NSSATAV *)NULL;
01805   }
01806 
01807   rv->ber.data = nss_ZAlloc(arenaOpt, atav->ber.size);
01808   if( (void *)NULL == rv->ber.data ) {
01809     (void)nss_ZFreeIf(rv->value);
01810     (void)nss_ZFreeIf(rv);
01811     return (NSSATAV *)NULL;
01812   }
01813 
01814   rv->ber.size = atav->ber.size;
01815   if( NULL == nsslibc_memcpy(rv->ber.data, atav->ber.data, 
01816                                    atav->ber.size) ) {
01817     (void)nss_ZFreeIf(rv->ber.data);
01818     (void)nss_ZFreeIf(rv->value);
01819     (void)nss_ZFreeIf(rv);
01820     return (NSSATAV *)NULL;
01821   }
01822 
01823   return rv;
01824 }