Imported Upstream version 3.13.6
[platform/upstream/nss.git] / mozilla / security / nss / lib / util / oidstring.c
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
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/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is the Network Security Services.
15  *
16  * The Initial Developer of the Original Code is Nelson B Bolyard
17  * Portions created by the Initial Developer are Copyright (C) 2007
18  * the Initial Developer. All Rights Reserved.
19  *
20  * Contributor(s):
21  *
22  * Alternatively, the contents of this file may be used under the terms of
23  * either the GNU General Public License Version 2 or later (the "GPL"), or
24  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25  * in which case the provisions of the GPL or the LGPL are applicable instead
26  * of those above. If you wish to allow use of your version of this file only
27  * under the terms of either the GPL or the LGPL, and not to allow others to
28  * use your version of this file under the terms of the MPL, indicate your
29  * decision by deleting the provisions above and replace them with the notice
30  * and other provisions required by the GPL or the LGPL. If you do not delete
31  * the provisions above, a recipient may use your version of this file under
32  * the terms of any one of the MPL, the GPL or the LGPL.
33  *
34  * ***** END LICENSE BLOCK ***** */
35
36 #include <string.h>
37 #include "secitem.h"
38 #include "secport.h"
39 #include "secerr.h"
40
41 /* if to->data is not NULL, and to->len is large enough to hold the result,
42  * then the resultant OID will be copyed into to->data, and to->len will be
43  * changed to show the actual OID length.
44  * Otherwise, memory for the OID will be allocated (from the caller's 
45  * PLArenaPool, if pool is non-NULL) and to->data will receive the address
46  * of the allocated data, and to->len will receive the OID length.
47  * The original value of to->data is not freed when a new buffer is allocated.
48  * 
49  * The input string may begin with "OID." and this still be ignored.
50  * The length of the input string is given in len.  If len == 0, then 
51  * len will be computed as strlen(from), meaning it must be NUL terminated.
52  * It is an error if from == NULL, or if *from == '\0'.
53  */
54
55 SECStatus
56 SEC_StringToOID(PLArenaPool *pool, SECItem *to, const char *from, PRUint32 len)
57 {
58     PRUint32 decimal_numbers = 0;
59     PRUint32 result_bytes = 0;
60     SECStatus rv;
61     PRUint8 result[1024];
62
63     static const PRUint32 max_decimal = (0xffffffff / 10);
64     static const char OIDstring[] = {"OID."};
65
66     if (!from || !to) {
67         PORT_SetError(SEC_ERROR_INVALID_ARGS);
68         return SECFailure;
69     }
70     if (!len) {
71         len = PL_strlen(from);
72     }
73     if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) {
74         from += 4; /* skip leading "OID." if present */
75         len  -= 4;
76     }
77     if (!len) {
78 bad_data:
79         PORT_SetError(SEC_ERROR_BAD_DATA);
80         return SECFailure;
81     }
82     do {
83         PRUint32 decimal = 0;
84         while (len > 0 && isdigit(*from)) {
85             PRUint32 addend = (*from++ - '0');
86             --len;
87             if (decimal > max_decimal)  /* overflow */
88                 goto bad_data;
89             decimal = (decimal * 10) + addend;
90             if (decimal < addend)       /* overflow */
91                 goto bad_data;
92         }
93         if (len != 0 && *from != '.') {
94             goto bad_data;
95         }
96         if (decimal_numbers == 0) {
97             if (decimal > 2)
98                 goto bad_data;
99             result[0] = decimal * 40;
100             result_bytes = 1;
101         } else if (decimal_numbers == 1) {
102             if (decimal > 40)
103                 goto bad_data;
104             result[0] += decimal;
105         } else {
106             /* encode the decimal number,  */
107             PRUint8 * rp;
108             PRUint32 num_bytes = 0;
109             PRUint32 tmp = decimal;
110             while (tmp) {
111                 num_bytes++;
112                 tmp >>= 7;
113             }
114             if (!num_bytes )
115                 ++num_bytes;  /* use one byte for a zero value */
116             if (num_bytes + result_bytes > sizeof result)
117                 goto bad_data;
118             tmp = num_bytes;
119             rp = result + result_bytes - 1;
120             rp[tmp] = (PRUint8)(decimal & 0x7f);
121             decimal >>= 7;
122             while (--tmp > 0) {
123                 rp[tmp] = (PRUint8)(decimal | 0x80);
124                 decimal >>= 7;
125             }
126             result_bytes += num_bytes;
127         }
128         ++decimal_numbers;
129         if (len > 0) { /* skip trailing '.' */
130             ++from;
131             --len;
132         }
133     } while (len > 0);
134     /* now result contains result_bytes of data */
135     if (to->data && to->len >= result_bytes) {
136         PORT_Memcpy(to->data, result, to->len = result_bytes);
137         rv = SECSuccess;
138     } else {
139         SECItem result_item = {siBuffer, NULL, 0 };
140         result_item.data = result;
141         result_item.len  = result_bytes;
142         rv = SECITEM_CopyItem(pool, to, &result_item);
143     }
144     return rv;
145 }