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