/src/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 | 5.73k | { |
27 | 5.73k | PRUint32 decimal_numbers = 0; |
28 | 5.73k | PRUint32 result_bytes = 0; |
29 | 5.73k | SECStatus rv; |
30 | 5.73k | PRUint8 result[1024]; |
31 | | |
32 | 5.73k | static const PRUint32 max_decimal = (0xffffffff / 10); |
33 | 5.73k | static const char OIDstring[] = { "OID." }; |
34 | | |
35 | 5.73k | if (!from || !to) { |
36 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
37 | 0 | return SECFailure; |
38 | 0 | } |
39 | 5.73k | if (!len) { |
40 | 0 | len = PL_strlen(from); |
41 | 0 | } |
42 | 5.73k | if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) { |
43 | 258 | from += 4; /* skip leading "OID." if present */ |
44 | 258 | len -= 4; |
45 | 258 | } |
46 | 5.73k | if (!len) { |
47 | 190 | bad_data: |
48 | 190 | PORT_SetError(SEC_ERROR_BAD_DATA); |
49 | 190 | return SECFailure; |
50 | 9 | } |
51 | 12.0k | do { |
52 | 12.0k | PRUint32 decimal = 0; |
53 | 24.9k | while (len > 0 && isdigit((unsigned char)*from)) { |
54 | 12.8k | PRUint32 addend = (*from++ - '0'); |
55 | 12.8k | --len; |
56 | 12.8k | if (decimal > max_decimal) /* overflow */ |
57 | 5 | goto bad_data; |
58 | 12.8k | decimal = (decimal * 10) + addend; |
59 | 12.8k | if (decimal < addend) /* overflow */ |
60 | 1 | goto bad_data; |
61 | 12.8k | } |
62 | 12.0k | if (len != 0 && *from != '.') { |
63 | 13 | goto bad_data; |
64 | 13 | } |
65 | 12.0k | if (decimal_numbers == 0) { |
66 | 5.70k | if (decimal > 2) |
67 | 109 | goto bad_data; |
68 | 5.60k | result[0] = decimal * 40; |
69 | 5.60k | result_bytes = 1; |
70 | 6.36k | } else if (decimal_numbers == 1) { |
71 | 1.80k | if (decimal > 40) |
72 | 53 | goto bad_data; |
73 | 1.75k | result[0] += decimal; |
74 | 4.56k | } else { |
75 | | /* encode the decimal number, */ |
76 | 4.56k | PRUint8 *rp; |
77 | 4.56k | PRUint32 num_bytes = 0; |
78 | 4.56k | PRUint32 tmp = decimal; |
79 | 8.18k | while (tmp) { |
80 | 3.62k | num_bytes++; |
81 | 3.62k | tmp >>= 7; |
82 | 3.62k | } |
83 | 4.56k | if (!num_bytes) |
84 | 2.40k | ++num_bytes; /* use one byte for a zero value */ |
85 | 4.56k | if (num_bytes + result_bytes > sizeof result) |
86 | 0 | goto bad_data; |
87 | 4.56k | tmp = num_bytes; |
88 | 4.56k | rp = result + result_bytes - 1; |
89 | 4.56k | rp[tmp] = (PRUint8)(decimal & 0x7f); |
90 | 4.56k | decimal >>= 7; |
91 | 6.02k | while (--tmp > 0) { |
92 | 1.46k | rp[tmp] = (PRUint8)(decimal | 0x80); |
93 | 1.46k | decimal >>= 7; |
94 | 1.46k | } |
95 | 4.56k | result_bytes += num_bytes; |
96 | 4.56k | } |
97 | 11.9k | ++decimal_numbers; |
98 | 11.9k | if (len > 0) { /* skip trailing '.' */ |
99 | 6.93k | ++from; |
100 | 6.93k | --len; |
101 | 6.93k | } |
102 | 11.9k | } while (len > 0); |
103 | | /* now result contains result_bytes of data */ |
104 | 5.54k | if (to->data && to->len >= result_bytes) { |
105 | 0 | PORT_Memcpy(to->data, result, to->len = result_bytes); |
106 | 0 | rv = SECSuccess; |
107 | 5.54k | } else { |
108 | 5.54k | SECItem result_item = { siBuffer, NULL, 0 }; |
109 | 5.54k | result_item.data = result; |
110 | 5.54k | result_item.len = result_bytes; |
111 | 5.54k | rv = SECITEM_CopyItem(pool, to, &result_item); |
112 | 5.54k | } |
113 | 5.54k | return rv; |
114 | 5.72k | } |