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