/src/nss-nspr/nss/lib/util/oidstring.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | #include <string.h> |
6 | | #include "secitem.h" |
7 | | #include "secport.h" |
8 | | #include "secerr.h" |
9 | | |
10 | | /* if to->data is not NULL, and to->len is large enough to hold the result, |
11 | | * then the resultant OID will be copyed into to->data, and to->len will be |
12 | | * changed to show the actual OID length. |
13 | | * Otherwise, memory for the OID will be allocated (from the caller's |
14 | | * PLArenaPool, if pool is non-NULL) and to->data will receive the address |
15 | | * of the allocated data, and to->len will receive the OID length. |
16 | | * The original value of to->data is not freed when a new buffer is allocated. |
17 | | * |
18 | | * The input string may begin with "OID." and this still be ignored. |
19 | | * The length of the input string is given in len. If len == 0, then |
20 | | * len will be computed as strlen(from), meaning it must be NUL terminated. |
21 | | * It is an error if from == NULL, or if *from == '\0'. |
22 | | */ |
23 | | |
24 | | SECStatus |
25 | | SEC_StringToOID(PLArenaPool *pool, SECItem *to, const char *from, PRUint32 len) |
26 | 0 | { |
27 | 0 | PRUint32 decimal_numbers = 0; |
28 | 0 | PRUint32 result_bytes = 0; |
29 | 0 | SECStatus rv; |
30 | 0 | PRUint8 result[1024]; |
31 | |
|
32 | 0 | static const PRUint32 max_decimal = (0xffffffff / 10); |
33 | 0 | static const char OIDstring[] = { "OID." }; |
34 | |
|
35 | 0 | if (!from || !to) { |
36 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
37 | 0 | return SECFailure; |
38 | 0 | } |
39 | 0 | if (!len) { |
40 | 0 | len = PL_strlen(from); |
41 | 0 | } |
42 | 0 | if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) { |
43 | 0 | from += 4; /* skip leading "OID." if present */ |
44 | 0 | len -= 4; |
45 | 0 | } |
46 | 0 | if (!len) { |
47 | 0 | bad_data: |
48 | 0 | PORT_SetError(SEC_ERROR_BAD_DATA); |
49 | 0 | return SECFailure; |
50 | 0 | } |
51 | 0 | do { |
52 | 0 | PRUint32 decimal = 0; |
53 | 0 | while (len > 0 && isdigit((unsigned char)*from)) { |
54 | 0 | PRUint32 addend = (*from++ - '0'); |
55 | 0 | --len; |
56 | 0 | if (decimal > max_decimal) /* overflow */ |
57 | 0 | goto bad_data; |
58 | 0 | decimal = (decimal * 10) + addend; |
59 | 0 | if (decimal < addend) /* overflow */ |
60 | 0 | goto bad_data; |
61 | 0 | } |
62 | 0 | if (len != 0 && *from != '.') { |
63 | 0 | goto bad_data; |
64 | 0 | } |
65 | 0 | if (decimal_numbers == 0) { |
66 | 0 | if (decimal > 2) |
67 | 0 | goto bad_data; |
68 | 0 | result[0] = decimal * 40; |
69 | 0 | result_bytes = 1; |
70 | 0 | } else if (decimal_numbers == 1) { |
71 | 0 | if (decimal > 40) |
72 | 0 | goto bad_data; |
73 | 0 | result[0] += decimal; |
74 | 0 | } else { |
75 | | /* encode the decimal number, */ |
76 | 0 | PRUint8 *rp; |
77 | 0 | PRUint32 num_bytes = 0; |
78 | 0 | PRUint32 tmp = decimal; |
79 | 0 | while (tmp) { |
80 | 0 | num_bytes++; |
81 | 0 | tmp >>= 7; |
82 | 0 | } |
83 | 0 | if (!num_bytes) |
84 | 0 | ++num_bytes; /* use one byte for a zero value */ |
85 | 0 | if (num_bytes + result_bytes > sizeof result) |
86 | 0 | goto bad_data; |
87 | 0 | tmp = num_bytes; |
88 | 0 | rp = result + result_bytes - 1; |
89 | 0 | rp[tmp] = (PRUint8)(decimal & 0x7f); |
90 | 0 | decimal >>= 7; |
91 | 0 | while (--tmp > 0) { |
92 | 0 | rp[tmp] = (PRUint8)(decimal | 0x80); |
93 | 0 | decimal >>= 7; |
94 | 0 | } |
95 | 0 | result_bytes += num_bytes; |
96 | 0 | } |
97 | 0 | ++decimal_numbers; |
98 | 0 | if (len > 0) { /* skip trailing '.' */ |
99 | 0 | ++from; |
100 | 0 | --len; |
101 | 0 | } |
102 | 0 | } while (len > 0); |
103 | | /* now result contains result_bytes of data */ |
104 | 0 | if (to->data && to->len >= result_bytes) { |
105 | 0 | PORT_Memcpy(to->data, result, to->len = result_bytes); |
106 | 0 | rv = SECSuccess; |
107 | 0 | } else { |
108 | 0 | SECItem result_item = { siBuffer, NULL, 0 }; |
109 | 0 | result_item.data = result; |
110 | 0 | result_item.len = result_bytes; |
111 | 0 | rv = SECITEM_CopyItem(pool, to, &result_item); |
112 | 0 | } |
113 | 0 | return rv; |
114 | 0 | } |