1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 static const char CVS_ID
[] = "@(#) $RCSfile: oid.c,v $ $Revision: 1.6 $ $Date: 2005/01/20 02:25:49 $";
44 * This file contains the implementation of the basic OID routines.
61 * The public "methods" regarding this "object" are:
63 * NSSOID_CreateFromBER -- constructor
64 * NSSOID_CreateFromUTF8 -- constructor
65 * (there is no explicit destructor)
67 * NSSOID_GetDEREncoding
68 * NSSOID_GetUTF8Encoding
70 * The non-public "methods" regarding this "object" are:
72 * nssOID_CreateFromBER -- constructor
73 * nssOID_CreateFromUTF8 -- constructor
74 * (there is no explicit destructor)
76 * nssOID_GetDEREncoding
77 * nssOID_GetUTF8Encoding
79 * In debug builds, the following non-public calls are also available:
81 * nssOID_verifyPointer
82 * nssOID_getExplanation
83 * nssOID_getTaggedUTF8
86 const NSSOID
*NSS_OID_UNKNOWN
= (NSSOID
*)NULL
;
89 * First, the public "wrappers"
93 * NSSOID_CreateFromBER
95 * This routine creates an NSSOID by decoding a BER- or DER-encoded
96 * OID. It may return NULL upon error, in which case it
97 * will have created an error stack.
99 * The error may be one of the following values:
100 * NSS_ERROR_INVALID_BER
101 * NSS_ERROR_NO_MEMORY
105 * An NSSOID upon success
114 nss_ClearErrorStack();
118 * NSSBERs can be created by the user,
119 * so no pointer-tracking can be checked.
122 if( (NSSBER
*)NULL
== berOid
) {
123 nss_SetError(NSS_ERROR_INVALID_BER
);
124 return (NSSOID
*)NULL
;
127 if( (void *)NULL
== berOid
->data
) {
128 nss_SetError(NSS_ERROR_INVALID_BER
);
129 return (NSSOID
*)NULL
;
133 return nssOID_CreateFromBER(berOid
);
137 * NSSOID_CreateFromUTF8
139 * This routine creates an NSSOID by decoding a UTF8 string
140 * representation of an OID in dotted-number format. The string may
141 * optionally begin with an octothorpe. It may return NULL
142 * upon error, in which case it will have created an error stack.
144 * The error may be one of the following values:
145 * NSS_ERROR_INVALID_UTF8
146 * NSS_ERROR_NO_MEMORY
150 * An NSSOID upon success
154 NSSOID_CreateFromUTF8
159 nss_ClearErrorStack();
163 * NSSUTF8s can be created by the user,
164 * so no pointer-tracking can be checked.
167 if( (NSSUTF8
*)NULL
== stringOid
) {
168 nss_SetError(NSS_ERROR_INVALID_UTF8
);
169 return (NSSOID
*)NULL
;
173 return nssOID_CreateFromUTF8(stringOid
);
177 * NSSOID_GetDEREncoding
179 * This routine returns the DER encoding of the specified NSSOID.
180 * If the optional arena argument is non-null, the memory used will
181 * be obtained from that arena; otherwise, the memory will be obtained
182 * from the heap. This routine may return return null upon error, in
183 * which case it will have created an error stack.
185 * The error may be one of the following values:
186 * NSS_ERROR_INVALID_NSSOID
187 * NSS_ERROR_NO_MEMORY
191 * The DER encoding of this NSSOID
195 NSSOID_GetDEREncoding
202 nss_ClearErrorStack();
205 if( PR_SUCCESS
!= nssOID_verifyPointer(oid
) ) {
206 return (NSSDER
*)NULL
;
209 if( (NSSArena
*)NULL
!= arenaOpt
) {
210 if( PR_SUCCESS
!= nssArena_verifyPointer(arenaOpt
) ) {
211 return (NSSDER
*)NULL
;
216 return nssOID_GetDEREncoding(oid
, rvOpt
, arenaOpt
);
220 * NSSOID_GetUTF8Encoding
222 * This routine returns a UTF8 string containing the dotted-number
223 * encoding of the specified NSSOID. If the optional arena argument
224 * is non-null, the memory used will be obtained from that arena;
225 * otherwise, the memory will be obtained from the heap. This routine
226 * may return null upon error, in which case it will have created an
229 * The error may be one of the following values:
230 * NSS_ERROR_INVALID_NSSOID
231 * NSS_ERROR_NO_MEMORY
235 * A pointer to a UTF8 string containing the dotted-digit encoding of
240 NSSOID_GetUTF8Encoding
246 nss_ClearErrorStack();
249 if( PR_SUCCESS
!= nssOID_verifyPointer(oid
) ) {
250 return (NSSUTF8
*)NULL
;
253 if( (NSSArena
*)NULL
!= arenaOpt
) {
254 if( PR_SUCCESS
!= nssArena_verifyPointer(arenaOpt
) ) {
255 return (NSSUTF8
*)NULL
;
260 return nssOID_GetUTF8Encoding(oid
, arenaOpt
);
264 * Next, some internal bookkeeping; including the OID "tag" table
265 * and the debug-version pointer tracker.
269 * For implementation reasons (so NSSOIDs can be compared with ==),
270 * we hash all NSSOIDs. This is the hash table.
273 static PLHashTable
*oid_hash_table
;
276 * And this is its lock.
279 static PZLock
*oid_hash_lock
;
282 * This is the hash function. We simply XOR the encoded form with
283 * itself in sizeof(PLHashNumber)-byte chunks. Improving this
284 * routine is left as an excercise for the more mathematically
288 static PLHashNumber PR_CALLBACK
294 const NSSItem
*item
= (const NSSItem
*)key
;
297 PRUint8
*data
= (PRUint8
*)item
->data
;
299 PRUint8
*rvc
= (PRUint8
*)&rv
;
301 for( i
= 0; i
< item
->size
; i
++ ) {
302 rvc
[ i
% sizeof(rv
) ] ^= *data
;
310 * This is the key-compare function. It simply does a lexical
311 * comparison on the encoded OID form. This does not result in
312 * quite the same ordering as the "sequence of numbers" order,
313 * but heck it's only used internally by the hash table anyway.
316 static PRIntn PR_CALLBACK
325 const NSSItem
*i1
= (const NSSItem
*)k1
;
326 const NSSItem
*i2
= (const NSSItem
*)k2
;
328 PRUint32 size
= (i1
->size
< i2
->size
) ? i1
->size
: i2
->size
;
330 rv
= (PRIntn
)nsslibc_memequal(i1
->data
, i2
->data
, size
, (PRStatus
*)NULL
);
332 rv
= i1
->size
- i2
->size
;
339 * The pointer-tracking code
343 extern const NSSError NSS_ERROR_INTERNAL_ERROR
;
345 static nssPointerTracker oid_pointer_tracker
;
355 rv
= nssPointerTracker_initialize(&oid_pointer_tracker
);
356 if( PR_SUCCESS
!= rv
) {
360 rv
= nssPointerTracker_add(&oid_pointer_tracker
, oid
);
361 if( PR_SUCCESS
!= rv
) {
362 NSSError e
= NSS_GetError();
363 if( NSS_ERROR_NO_MEMORY
!= e
) {
364 nss_SetError(NSS_ERROR_INTERNAL_ERROR
);
373 #if defined(CAN_DELETE_OIDS)
375 * We actually don't define NSSOID deletion, since we keep OIDs
376 * in a hash table for easy comparison. Were we to, this is
377 * what the pointer-removal function would look like.
388 rv
= nssPointerTracker_remove(&oid_pointer_tracker
, oid
);
389 if( PR_SUCCESS
!= rv
) {
390 nss_SetError(NSS_ERROR_INTERNAL_ERROR
);
395 #endif /* CAN_DELETE_OIDS */
400 * All dynamically-added OIDs get their memory from one statically-
401 * declared arena here, merely so that any cleanup code will have
402 * an easier time of it.
405 static NSSArena
*oid_arena
;
408 * This is the call-once function which initializes the hashtable.
409 * It creates it, then prepopulates it with all of the builtin OIDs.
410 * It also creates the aforementioned NSSArena.
413 static PRStatus PR_CALLBACK
421 /* Initialize the arena */
422 oid_arena
= nssArena_Create();
423 if( (NSSArena
*)NULL
== oid_arena
) {
427 /* Create the hash table lock */
428 oid_hash_lock
= PZ_NewLock(nssILockOID
);
429 if( (PZLock
*)NULL
== oid_hash_lock
) {
430 nss_SetError(NSS_ERROR_NO_MEMORY
);
434 /* Create the hash table */
435 oid_hash_table
= PL_NewHashTable(0, oid_hash
, oid_hash_compare
,
439 if( (PLHashTable
*)NULL
== oid_hash_table
) {
440 nss_SetError(NSS_ERROR_NO_MEMORY
);
444 /* And populate it with all the builtins */
445 for( i
= 0; i
< nss_builtin_oid_count
; i
++ ) {
446 NSSOID
*oid
= (NSSOID
*)&nss_builtin_oids
[i
];
447 PLHashEntry
*e
= PL_HashTableAdd(oid_hash_table
, &oid
->data
, oid
);
448 if( (PLHashEntry
*)NULL
== e
) {
449 nss_SetError(NSS_ERROR_NO_MEMORY
);
454 if( PR_SUCCESS
!= oid_add_pointer(oid
) ) {
463 if( (PLHashTable
*)NULL
!= oid_hash_table
) {
464 PL_HashTableDestroy(oid_hash_table
);
465 oid_hash_table
= (PLHashTable
*)NULL
;
468 if( (PZLock
*)NULL
!= oid_hash_lock
) {
469 PZ_DestroyLock(oid_hash_lock
);
470 oid_hash_lock
= (PZLock
*)NULL
;
473 if( (NSSArena
*)NULL
!= oid_arena
) {
474 (void)nssArena_Destroy(oid_arena
);
475 oid_arena
= (NSSArena
*)NULL
;
482 * This is NSPR's once-block.
485 static PRCallOnceType oid_call_once
;
488 * And this is our multiply-callable internal init routine, which
489 * will call-once our call-once function.
498 return PR_CallOnce(&oid_call_once
, oid_once_func
);
504 * nssOID_verifyPointer
506 * This method is only present in debug builds.
508 * If the specified pointer is a valid pointer to an NSSOID object,
509 * this routine will return PR_SUCCESS. Otherwise, it will put an
510 * error on the error stack and return PR_FAILURE.
512 * The error may be one of the following values:
513 * NSS_ERROR_INVALID_NSSOID
514 * NSS_ERROR_NO_MEMORY
517 * PR_SUCCESS if the pointer is valid
518 * PR_FAILURE if it isn't
530 if( PR_SUCCESS
!= rv
) {
534 rv
= nssPointerTracker_initialize(&oid_pointer_tracker
);
535 if( PR_SUCCESS
!= rv
) {
539 rv
= nssPointerTracker_verify(&oid_pointer_tracker
, oid
);
540 if( PR_SUCCESS
!= rv
) {
541 nss_SetError(NSS_ERROR_INVALID_NSSOID
);
550 * oid_sanity_check_ber
552 * This routine merely applies some sanity-checking to the BER-encoded
563 PRUint8
*data
= (PRUint8
*)berOid
->data
;
566 * The size must be longer than zero bytes.
569 if( berOid
->size
<= 0 ) {
574 * In general, we can't preclude any number from showing up
575 * someday. We could probably guess that top-level numbers
576 * won't get very big (beyond the current ccitt(0), iso(1),
577 * or joint-ccitt-iso(2)). However, keep in mind that the
578 * encoding rules wrap the first two numbers together, as
580 * (first * 40) + second
582 * Also, it is noted in the specs that this implies that the
583 * second number won't go above forty.
585 * 128 encodes 3.8, which seems pretty safe for now. Let's
586 * check that the first byte is less than that.
588 * XXX This is a "soft check" -- we may want to exclude it.
591 if( data
[0] >= 0x80 ) {
596 * In a normalised format, leading 0x80s will never show up.
597 * This means that no 0x80 will be preceeded by the final
598 * byte of a sequence, which would naturaly be less than 0x80.
599 * Our internal encoding for the single-digit OIDs uses 0x80,
600 * but the only places we use them (loading the builtin table,
601 * and adding a UTF8-encoded OID) bypass this check.
604 for( i
= 1; i
< berOid
->size
; i
++ ) {
605 if( (0x80 == data
[i
]) && (data
[i
-1] < 0x80) ) {
611 * The high bit of each octet indicates that following octets
612 * are included in the current number. Thus the last byte can't
613 * have the high bit set.
616 if( data
[ berOid
->size
-1 ] >= 0x80 ) {
621 * Other than that, any byte sequence is legit.
627 * nssOID_CreateFromBER
629 * This routine creates an NSSOID by decoding a BER- or DER-encoded
630 * OID. It may return NULL upon error, in which case it
631 * will have set an error on the error stack.
633 * The error may be one of the following values:
634 * NSS_ERROR_INVALID_BER
635 * NSS_ERROR_NO_MEMORY
639 * An NSSOID upon success
651 if( PR_SUCCESS
!= oid_init() ) {
652 return (NSSOID
*)NULL
;
655 if( PR_SUCCESS
!= oid_sanity_check_ber(berOid
) ) {
656 nss_SetError(NSS_ERROR_INVALID_BER
);
657 return (NSSOID
*)NULL
;
663 PZ_Lock(oid_hash_lock
);
664 rv
= (NSSOID
*)PL_HashTableLookup(oid_hash_table
, berOid
);
665 (void)PZ_Unlock(oid_hash_lock
);
666 if( (NSSOID
*)NULL
!= rv
) {
672 * Doesn't exist-- create it.
674 rv
= nss_ZNEW(oid_arena
, NSSOID
);
675 if( (NSSOID
*)NULL
== rv
) {
676 return (NSSOID
*)NULL
;
679 rv
->data
.data
= nss_ZAlloc(oid_arena
, berOid
->size
);
680 if( (void *)NULL
== rv
->data
.data
) {
681 return (NSSOID
*)NULL
;
684 rv
->data
.size
= berOid
->size
;
685 nsslibc_memcpy(rv
->data
.data
, berOid
->data
, berOid
->size
);
688 rv
->tag
= "<runtime>";
689 rv
->expl
= "(OID registered at runtime)";
692 PZ_Lock(oid_hash_lock
);
693 e
= PL_HashTableAdd(oid_hash_table
, &rv
->data
, rv
);
694 (void)PZ_Unlock(oid_hash_lock
);
695 if( (PLHashEntry
*)NULL
== e
) {
696 nss_ZFreeIf(rv
->data
.data
);
698 nss_SetError(NSS_ERROR_NO_MEMORY
);
699 return (NSSOID
*)NULL
;
705 st
= oid_add_pointer(rv
);
706 if( PR_SUCCESS
!= st
) {
707 PZ_Lock(oid_hash_lock
);
708 (void)PL_HashTableRemove(oid_hash_table
, &rv
->data
);
709 (void)PZ_Unlock(oid_hash_lock
);
710 (void)nss_ZFreeIf(rv
->data
.data
);
711 (void)nss_ZFreeIf(rv
);
712 return (NSSOID
*)NULL
;
721 * oid_sanity_check_utf8
723 * This routine merely applies some sanity-checking to the
728 oid_sanity_check_utf8
734 * It may begin with an octothorpe, which we skip.
742 * It begins with a number
745 if( (*s
< '0') || (*s
> '9') ) {
750 * First number is only one digit long
752 * XXX This is a "soft check" -- we may want to exclude it
755 if( (s
[1] != '.') && (s
[1] != '\0') ) {
760 * Every character is either a digit or a period
763 for( ; '\0' != *s
; s
++ ) {
764 if( ('.' != *s
) && ((*s
< '0') || (*s
> '9')) ) {
768 /* No two consecutive periods */
769 if( ('.' == *s
) && ('.' == s
[1]) ) {
775 * The last character isn't a period
797 a
[0] = (n
>> 28) & 0x7f;
798 a
[1] = (n
>> 21) & 0x7f;
799 a
[2] = (n
>> 14) & 0x7f;
800 a
[3] = (n
>> 7) & 0x7f;
803 for( i
= 0; i
< 5; i
++ ) {
818 for( ; i
< 4; i
++ ) {
831 * This routine will convert a huge decimal number into the DER
832 * encoding for oid numbers. It is not limited to numbers that will
833 * fit into some wordsize, like oid_encode_number. But it's not
834 * necessarily very fast, either. This is here in case some joker
835 * throws us an ASCII oid like 1.2.3.99999999999999999999999999.
847 PRUint32 slen
= (e
-s
);
848 PRUint32 blen
= (slen
+1)/2;
849 PRUint8
*st
= (PRUint8
*)NULL
;
850 PRUint8
*bd
= (PRUint8
*)NULL
;
858 /* We'll be munging the data, so duplicate it */
859 st
= (PRUint8
*)nss_ZAlloc((NSSArena
*)NULL
, slen
);
860 if( (PRUint8
*)NULL
== st
) {
864 /* Don't know ahead of time exactly how long we'll need */
865 bd
= (PRUint8
*)nss_ZAlloc((NSSArena
*)NULL
, blen
);
866 if( (PRUint8
*)NULL
== bd
) {
867 (void)nss_ZFreeIf(st
);
871 /* Copy the original, and convert ASCII to numbers */
872 for( i
= 0; i
< slen
; i
++ ) {
873 st
[i
] = (PRUint8
)(s
[i
] - '0');
880 * The way we create the binary version is by looking at it
881 * bit by bit. Start with the least significant bit. If the
882 * number is odd, set that bit. Halve the number (with integer
883 * division), and go to the next least significant bit. Keep
884 * going until the number goes to zero.
886 for( bitno
= 0; ; bitno
++ ) {
890 mask
= (PRUint8
)(1 << (bitno
%7));
892 /* Skip leading zeroes */
893 for( ; first
< last
; first
++ ) {
899 /* Down to one number and it's a zero? Done. */
900 if( (first
== last
) && (0 == *last
) ) {
904 /* Last digit is odd? Set the bit */
906 bd
[ byteno
] |= mask
;
911 * Divide the number in half. This is just a matter
912 * of going from the least significant digit upwards,
913 * halving each one. If any digit is odd (other than
914 * the last, which has already been handled), add five
915 * to the digit to its right.
919 for( d
= &last
[-1]; d
>= first
; d
-- ) {
928 /* Is there room to write the encoded data? */
929 if( (byteno
+1) > nb
) {
933 /* Trim any leading zero that crept in there */
934 for( ; byteno
> 0; byteno
-- ) {
935 if( 0 != bd
[ byteno
] ) {
940 /* Copy all but the last, marking the "continue" bit */
941 for( i
= 0; i
< byteno
; i
++ ) {
942 dp
[i
] = bd
[ byteno
-i
] | 0x80;
944 /* And the last with the "continue" bit clear */
947 (void)nss_ZFreeIf(bd
);
948 (void)nss_ZFreeIf(st
);
955 * This routine converts a dotted-number OID into a DER-encoded
956 * one. It assumes we've already sanity-checked the string.
959 extern const NSSError NSS_ERROR_INTERNAL_ERROR
;
967 PRUint32 nn
= 0; /* number of numbers */
968 PRUint32 nb
= 0; /* number of bytes (estimated) */
970 PRUint32 nd
= 0; /* number of digits */
976 /* Dump any octothorpe */
981 /* Count up the bytes needed */
982 for( t
= s
; '\0' != *t
; t
++ ) {
984 nb
+= (nd
+1)/2; /* errs on the big side */
996 * We have our own "denormalised" encoding for these,
997 * which is only used internally.
1003 * Allocate. Note that we don't use the oid_arena here.. this is
1004 * because there really isn't a "free()" for stuff allocated out of
1005 * arenas (at least with the current implementation), so this would
1006 * keep using up memory each time a UTF8-encoded OID were added.
1007 * If need be (if this is the first time this oid has been seen),
1010 rv
= nss_ZNEW((NSSArena
*)NULL
, NSSOID
);
1011 if( (NSSOID
*)NULL
== rv
) {
1012 return (NSSOID
*)NULL
;
1015 rv
->data
.data
= nss_ZAlloc((NSSArena
*)NULL
, nb
);
1016 if( (void *)NULL
== rv
->data
.data
) {
1017 (void)nss_ZFreeIf(rv
);
1018 return (NSSOID
*)NULL
;
1021 dp
= (PRUint8
*)rv
->data
.data
;
1027 inc
= oid_encode_number(a
, &dp
[1], nb
-1);
1032 for( t
= s
; '.' != *t
; t
++ ) {
1038 inc
= oid_encode_number(a
*40+b
, dp
, nb
);
1049 for( ; '.' != *t
; t
++ ) {
1055 for( u
= t
; ('\0' != *u
) && ('.' != *u
); u
++ ) {
1060 /* In the billions. Rats. */
1061 inc
= oid_encode_huge(t
, u
, dp
, nb
);
1064 inc
= oid_encode_number(b
, dp
, nb
);
1078 nss_SetError(NSS_ERROR_INTERNAL_ERROR
);
1079 return (NSSOID
*)NULL
;
1083 * nssOID_CreateFromUTF8
1085 * This routine creates an NSSOID by decoding a UTF8 string
1086 * representation of an OID in dotted-number format. The string may
1087 * optionally begin with an octothorpe. It may return NULL
1088 * upon error, in which case it will have set an error on the error
1091 * The error may be one of the following values:
1092 * NSS_ERROR_INVALID_STRING
1093 * NSS_ERROR_NO_MEMORY
1097 * An NSSOID upon success
1101 nssOID_CreateFromUTF8
1106 NSSOID
*rv
= (NSSOID
*)NULL
;
1107 NSSOID
*candidate
= (NSSOID
*)NULL
;
1110 if( PR_SUCCESS
!= oid_init() ) {
1111 return (NSSOID
*)NULL
;
1114 if( PR_SUCCESS
!= oid_sanity_check_utf8(stringOid
) ) {
1115 nss_SetError(NSS_ERROR_INVALID_STRING
);
1116 return (NSSOID
*)NULL
;
1119 candidate
= oid_encode_string(stringOid
);
1120 if( (NSSOID
*)NULL
== candidate
) {
1121 /* Internal error only */
1128 PZ_Lock(oid_hash_lock
);
1129 rv
= (NSSOID
*)PL_HashTableLookup(oid_hash_table
, &candidate
->data
);
1130 (void)PZ_Unlock(oid_hash_lock
);
1131 if( (NSSOID
*)NULL
!= rv
) {
1132 /* Already exists. Delete my copy and return the original. */
1133 (void)nss_ZFreeIf(candidate
->data
.data
);
1134 (void)nss_ZFreeIf(candidate
);
1139 * Nope. Add it. Remember to allocate it out of the oid arena.
1142 rv
= nss_ZNEW(oid_arena
, NSSOID
);
1143 if( (NSSOID
*)NULL
== rv
) {
1147 rv
->data
.data
= nss_ZAlloc(oid_arena
, candidate
->data
.size
);
1148 if( (void *)NULL
== rv
->data
.data
) {
1152 rv
->data
.size
= candidate
->data
.size
;
1153 nsslibc_memcpy(rv
->data
.data
, candidate
->data
.data
, rv
->data
.size
);
1155 (void)nss_ZFreeIf(candidate
->data
.data
);
1156 (void)nss_ZFreeIf(candidate
);
1159 rv
->tag
= "<runtime>";
1160 rv
->expl
= "(OID registered at runtime)";
1163 PZ_Lock(oid_hash_lock
);
1164 e
= PL_HashTableAdd(oid_hash_table
, &rv
->data
, rv
);
1165 (void)PZ_Unlock(oid_hash_lock
);
1166 if( (PLHashEntry
*)NULL
== e
) {
1167 nss_SetError(NSS_ERROR_NO_MEMORY
);
1174 st
= oid_add_pointer(rv
);
1175 if( PR_SUCCESS
!= st
) {
1176 PZ_Lock(oid_hash_lock
);
1177 (void)PL_HashTableRemove(oid_hash_table
, &rv
->data
);
1178 (void)PZ_Unlock(oid_hash_lock
);
1187 if( (NSSOID
*)NULL
!= candidate
) {
1188 (void)nss_ZFreeIf(candidate
->data
.data
);
1190 (void)nss_ZFreeIf(candidate
);
1192 if( (NSSOID
*)NULL
!= rv
) {
1193 (void)nss_ZFreeIf(rv
->data
.data
);
1195 (void)nss_ZFreeIf(rv
);
1197 return (NSSOID
*)NULL
;
1201 * nssOID_GetDEREncoding
1203 * This routine returns the DER encoding of the specified NSSOID.
1204 * If the optional arena argument is non-null, the memory used will
1205 * be obtained from that arena; otherwise, the memory will be obtained
1206 * from the heap. This routine may return return null upon error, in
1207 * which case it will have set an error on the error stack.
1209 * The error may be one of the following values:
1210 * NSS_ERROR_INVALID_OID
1211 * NSS_ERROR_NO_MEMORY
1215 * The DER encoding of this NSSOID
1219 nssOID_GetDEREncoding
1229 if( PR_SUCCESS
!= oid_init() ) {
1230 return (NSSDER
*)NULL
;
1234 if( PR_SUCCESS
!= nssOID_verifyPointer(oid
) ) {
1235 return (NSSDER
*)NULL
;
1238 if( (NSSArena
*)NULL
!= arenaOpt
) {
1239 if( PR_SUCCESS
!= nssArena_verifyPointer(arenaOpt
) ) {
1240 return (NSSDER
*)NULL
;
1243 #endif /* NSSDEBUG */
1247 if( (NSSDER
*)NULL
== rvOpt
) {
1248 rv
= nss_ZNEW(arenaOpt
, NSSDER
);
1249 if( (NSSDER
*)NULL
== rv
) {
1250 return (NSSDER
*)NULL
;
1256 rv
->data
= nss_ZAlloc(arenaOpt
, it
->size
);
1257 if( (void *)NULL
== rv
->data
) {
1259 (void)nss_ZFreeIf(rv
);
1261 return (NSSDER
*)NULL
;
1264 rv
->size
= it
->size
;
1265 nsslibc_memcpy(rv
->data
, it
->data
, it
->size
);
1271 * nssOID_GetUTF8Encoding
1273 * This routine returns a UTF8 string containing the dotted-number
1274 * encoding of the specified NSSOID. If the optional arena argument
1275 * is non-null, the memory used will be obtained from that arena;
1276 * otherwise, the memory will be obtained from the heap. This routine
1277 * may return null upon error, in which case it will have set an error
1278 * on the error stack.
1280 * The error may be one of the following values:
1281 * NSS_ERROR_INVALID_OID
1282 * NSS_ERROR_NO_MEMORY
1286 * A pointer to a UTF8 string containing the dotted-digit encoding of
1290 NSS_EXTERN NSSUTF8
*
1291 nssOID_GetUTF8Encoding
1305 if( PR_SUCCESS
!= oid_init() ) {
1306 return (NSSUTF8
*)NULL
;
1310 if( PR_SUCCESS
!= nssOID_verifyPointer(oid
) ) {
1311 return (NSSUTF8
*)NULL
;
1314 if( (NSSArena
*)NULL
!= arenaOpt
) {
1315 if( PR_SUCCESS
!= nssArena_verifyPointer(arenaOpt
) ) {
1316 return (NSSUTF8
*)NULL
;
1319 #endif /* NSSDEBUG */
1323 /* d will point to the next sequence of bytes to decode */
1324 d
= (PRUint8
*)oid
->data
.data
;
1325 /* end points to one past the legitimate data */
1326 end
= &d
[ oid
->data
.size
];
1330 * Guarantee that the for(e=d;e<end;e++) loop below will
1331 * terminate. Our BER sanity-checking code above will prevent
1332 * such a BER from being registered, so the only other way one
1333 * might show up is if our dotted-decimal encoder above screws
1334 * up or our generated list is wrong. So I'll wrap it with
1335 * #ifdef NSSDEBUG and #endif.
1337 if( end
[-1] & 0x80 ) {
1338 nss_SetError(NSS_ERROR_INTERNAL_ERROR
);
1339 return (NSSUTF8
*)NULL
;
1341 #endif /* NSSDEBUG */
1344 * Check for our pseudo-encoded single-digit OIDs
1346 if( (*d
== 0x80) && (2 == oid
->data
.size
) ) {
1347 /* Funky encoding. The second byte is the number */
1348 a
= PR_smprintf("%lu", (PRUint32
)d
[1]);
1349 if( (char *)NULL
== a
) {
1350 nss_SetError(NSS_ERROR_NO_MEMORY
);
1351 return (NSSUTF8
*)NULL
;
1356 for( ; d
< end
; d
= &e
[1] ) {
1358 for( e
= d
; e
< end
; e
++ ) {
1359 if( 0 == (*e
& 0x80) ) {
1364 if( ((e
-d
) > 4) || (((e
-d
) == 4) && (*d
& 0x70)) ) {
1365 /* More than a 32-bit number */
1371 n
|= ((PRUint32
)(e
[-4] & 0x0f)) << 28;
1373 n
|= ((PRUint32
)(e
[-3] & 0x7f)) << 21;
1375 n
|= ((PRUint32
)(e
[-2] & 0x7f)) << 14;
1377 n
|= ((PRUint32
)(e
[-1] & 0x7f)) << 7;
1379 n
|= ((PRUint32
)(e
[-0] & 0x7f)) ;
1382 if( (char *)NULL
== a
) {
1383 /* This is the first number.. decompose it */
1384 PRUint32 one
= (n
/40), two
= (n
%40);
1386 a
= PR_smprintf("%lu.%lu", one
, two
);
1387 if( (char *)NULL
== a
) {
1388 nss_SetError(NSS_ERROR_NO_MEMORY
);
1389 return (NSSUTF8
*)NULL
;
1392 b
= PR_smprintf("%s.%lu", a
, n
);
1393 if( (char *)NULL
== b
) {
1394 PR_smprintf_free(a
);
1395 nss_SetError(NSS_ERROR_NO_MEMORY
);
1396 return (NSSUTF8
*)NULL
;
1399 PR_smprintf_free(a
);
1407 * Even if arenaOpt is NULL, we have to copy the data so that
1408 * it'll be freed with the right version of free: ours, not
1409 * PR_smprintf_free's.
1412 rv
= (NSSUTF8
*)nss_ZAlloc(arenaOpt
, len
);
1413 if( (NSSUTF8
*)NULL
== rv
) {
1414 PR_smprintf_free(a
);
1415 return (NSSUTF8
*)NULL
;
1418 nsslibc_memcpy(rv
, a
, len
);
1419 PR_smprintf_free(a
);
1425 * nssOID_getExplanation
1427 * This method is only present in debug builds.
1429 * This routine will return a static pointer to a UTF8-encoded string
1430 * describing (in English) the specified OID. The memory pointed to
1431 * by the return value is not owned by the caller, and should not be
1432 * freed or modified. Note that explanations are only provided for
1433 * the OIDs built into the NSS library; there is no way to specify an
1434 * explanation for dynamically created OIDs. This routine is intended
1435 * only for use in debugging tools such as "derdump." This routine
1436 * may return null upon error, in which case it will have placed an
1437 * error on the error stack.
1439 * The error may be one of the following values:
1440 * NSS_ERROR_INVALID_NSSOID
1444 * A static pointer to a readonly, non-caller-owned UTF8-encoded
1445 * string explaining the specified OID.
1449 NSS_EXTERN
const NSSUTF8
*
1450 nssOID_getExplanation
1455 if( PR_SUCCESS
!= oid_init() ) {
1456 return (const NSSUTF8
*)NULL
;
1460 if( PR_SUCCESS
!= nssOID_verifyPointer(oid
) ) {
1461 return (NSSUTF8
*)NULL
;
1463 #endif /* NSSDEBUG */
1468 extern const NSSError NSS_ERROR_INVALID_NSSOID
;
1472 * nssOID_getTaggedUTF8
1474 * This method is only present in debug builds.
1476 * This routine will return a pointer to a caller-owned UTF8-encoded
1477 * string containing a tagged encoding of the specified OID. Note
1478 * that OID (component) tags are only provided for the OIDs built
1479 * into the NSS library; there is no way to specify tags for
1480 * dynamically created OIDs. This routine is intended for use in
1481 * debugging tools such as "derdump." If the optional arena argument
1482 * is non-null, the memory used will be obtained from that arena;
1483 * otherwise, the memory will be obtained from the heap. This routine
1484 * may return return null upon error, in which case it will have set
1485 * an error on the error stack.
1487 * The error may be one of the following values
1488 * NSS_ERROR_INVALID_NSSOID
1489 * NSS_ERROR_NO_MEMORY
1493 * A pointer to a UTF8 string containing the tagged encoding of
1498 NSS_EXTERN NSSUTF8
*
1499 nssOID_getTaggedUTF8
1508 char *a
= (char *)NULL
;
1510 PRBool done
= PR_FALSE
;
1513 if( PR_SUCCESS
!= oid_init() ) {
1514 return (NSSUTF8
*)NULL
;
1518 if( PR_SUCCESS
!= nssOID_verifyPointer(oid
) ) {
1519 return (NSSUTF8
*)NULL
;
1522 if( (NSSArena
*)NULL
!= arenaOpt
) {
1523 if( PR_SUCCESS
!= nssArena_verifyPointer(arenaOpt
) ) {
1524 return (NSSUTF8
*)NULL
;
1527 #endif /* NSSDEBUG */
1529 a
= PR_smprintf("{");
1530 if( (char *)NULL
== a
) {
1531 nss_SetError(NSS_ERROR_NO_MEMORY
);
1532 return (NSSUTF8
*)NULL
;
1536 * What I'm doing here is getting the text version of the OID,
1537 * e.g. 1.2.12.92, then looking up each set of leading numbers
1538 * as oids.. e.g. "1," then "1.2," then "1.2.12," etc. Each of
1539 * those will have the leaf tag, and I just build up the string.
1540 * I never said this was the most efficient way of doing it,
1541 * but hey it's a debug-build thing, and I'm getting really tired
1542 * of writing this stupid low-level PKI code.
1545 /* I know it's all ASCII, so I can use char */
1546 raw
= (char *)nssOID_GetUTF8Encoding(oid
, (NSSArena
*)NULL
);
1547 if( (char *)NULL
== raw
) {
1548 return (NSSUTF8
*)NULL
;
1551 for( c
= raw
; !done
; c
++ ) {
1555 for( ; '.' != *c
; c
++ ) {
1563 lead
= nssOID_CreateFromUTF8((NSSUTF8
*)raw
);
1564 if( (NSSOID
*)NULL
== lead
) {
1565 PR_smprintf_free(a
);
1567 nss_SetError(NSS_ERROR_NO_MEMORY
);
1568 return (NSSUTF8
*)NULL
;
1571 lastdot
= PL_strrchr(raw
, '.');
1572 if( (char *)NULL
== lastdot
) {
1576 b
= PR_smprintf("%s %s(%s) ", a
, lead
->tag
, &lastdot
[1]);
1577 if( (char *)NULL
== b
) {
1578 PR_smprintf_free(a
);
1580 /* drop the OID reference on the floor */
1581 nss_SetError(NSS_ERROR_NO_MEMORY
);
1582 return (NSSUTF8
*)NULL
;
1585 PR_smprintf_free(a
);
1595 b
= PR_smprintf("%s }", a
);
1596 if( (char *)NULL
== b
) {
1597 PR_smprintf_free(a
);
1598 nss_SetError(NSS_ERROR_NO_MEMORY
);
1599 return (NSSUTF8
*)NULL
;
1604 rv
= (NSSUTF8
*)nss_ZAlloc(arenaOpt
, len
+1);
1605 if( (NSSUTF8
*)NULL
== rv
) {
1606 PR_smprintf_free(b
);
1607 return (NSSUTF8
*)NULL
;
1610 nsslibc_memcpy(rv
, b
, len
);
1611 PR_smprintf_free(b
);
1616 extern const NSSError NSS_ERROR_INVALID_NSSOID
;
1617 extern const NSSError NSS_ERROR_NO_MEMORY
;