oidstring.c 3.7 KB

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