oid.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,616 行 · 第 1/3 页

C
1,616
字号
  }  return PR_SUCCESS;}#endif /* DEBUG *//* * oid_sanity_check_ber * * This routine merely applies some sanity-checking to the BER-encoded * OID. */static PRStatusoid_sanity_check_ber(  NSSBER *berOid){  PRUint32 i;  PRUint8 *data = (PRUint8 *)berOid->data;  /*   * The size must be longer than zero bytes.   */  if( berOid->size <= 0 ) {    return PR_FAILURE;  }  /*   * In general, we can't preclude any number from showing up   * someday.  We could probably guess that top-level numbers   * won't get very big (beyond the current ccitt(0), iso(1),   * or joint-ccitt-iso(2)).  However, keep in mind that the   * encoding rules wrap the first two numbers together, as   *   *     (first * 40) + second   *   * Also, it is noted in the specs that this implies that the   * second number won't go above forty.   *   * 128 encodes 3.8, which seems pretty safe for now.  Let's   * check that the first byte is less than that.   *   * XXX This is a "soft check" -- we may want to exclude it.   */  if( data[0] >= 0x80 ) {    return PR_FAILURE;  }  /*   * In a normalised format, leading 0x80s will never show up.   * This means that no 0x80 will be preceeded by the final   * byte of a sequence, which would naturaly be less than 0x80.   * Our internal encoding for the single-digit OIDs uses 0x80,   * but the only places we use them (loading the builtin table,   * and adding a UTF8-encoded OID) bypass this check.   */  for( i = 1; i < berOid->size; i++ ) {    if( (0x80 == data[i]) && (data[i-1] < 0x80) ) {      return PR_FAILURE;    }  }  /*   * The high bit of each octet indicates that following octets   * are included in the current number.  Thus the last byte can't   * have the high bit set.   */  if( data[ berOid->size-1 ] >= 0x80 ) {    return PR_FAILURE;  }  /*   * Other than that, any byte sequence is legit.   */  return PR_SUCCESS;}/* * nssOID_CreateFromBER * * This routine creates an NSSOID by decoding a BER- or DER-encoded * OID.  It may return NULL upon error, in which case it  * will have set an error on the error stack. * * The error may be one of the following values: *  NSS_ERROR_INVALID_BER *  NSS_ERROR_NO_MEMORY * * Return value: *  NULL upon error *  An NSSOID upon success */NSS_EXTERN NSSOID *nssOID_CreateFromBER(  NSSBER *berOid){  NSSOID *rv;  PLHashEntry *e;    if( PR_SUCCESS != oid_init() ) {    return (NSSOID *)NULL;  }  if( PR_SUCCESS != oid_sanity_check_ber(berOid) ) {    nss_SetError(NSS_ERROR_INVALID_BER);    return (NSSOID *)NULL;  }  /*   * Does it exist?   */  PR_Lock(oid_hash_lock);  rv = (NSSOID *)PL_HashTableLookup(oid_hash_table, berOid);  (void)PR_Unlock(oid_hash_lock);  if( (NSSOID *)NULL != rv ) {    /* Found it! */    return rv;  }  /*   * Doesn't exist-- create it.   */  rv = nss_ZNEW(oid_arena, NSSOID);  if( (NSSOID *)NULL == rv ) {    return (NSSOID *)NULL;  }  rv->data.data = nss_ZAlloc(oid_arena, berOid->size);  if( (void *)NULL == rv->data.data ) {    return (NSSOID *)NULL;  }  rv->data.size = berOid->size;  nsslibc_memcpy(rv->data.data, berOid->data, berOid->size);#ifdef DEBUG  rv->tag = "<runtime>";  rv->expl = "(OID registered at runtime)";#endif /* DEBUG */  PR_Lock(oid_hash_lock);  e = PL_HashTableAdd(oid_hash_table, &rv->data, rv);  (void)PR_Unlock(oid_hash_lock);  if( (PLHashEntry *)NULL == e ) {    nss_ZFreeIf(rv->data.data);    nss_ZFreeIf(rv);    nss_SetError(NSS_ERROR_NO_MEMORY);    return (NSSOID *)NULL;  }#ifdef DEBUG  {    PRStatus st;    st = oid_add_pointer(rv);    if( PR_SUCCESS != st ) {      PR_Lock(oid_hash_lock);      (void)PL_HashTableRemove(oid_hash_table, &rv->data);      (void)PR_Unlock(oid_hash_lock);      (void)nss_ZFreeIf(rv->data.data);      (void)nss_ZFreeIf(rv);      return (NSSOID *)NULL;    }  }#endif /* DEBUG */  return rv;}/* * oid_sanity_check_utf8 * * This routine merely applies some sanity-checking to the  * UTF8-encoded OID. */static PRStatusoid_sanity_check_utf8(  NSSUTF8 *s){  /*   * It may begin with an octothorpe, which we skip.   */  if( '#' == *s ) {    s++;  }  /*   * It begins with a number   */  if( (*s < '0') || (*s > '9') ) {    return PR_FAILURE;  }  /*   * First number is only one digit long   *   * XXX This is a "soft check" -- we may want to exclude it   */  if( (s[1] != '.') && (s[1] != '\0') ) {    return PR_FAILURE;  }  /*   * Every character is either a digit or a period   */  for( ; '\0' != *s; s++ ) {    if( ('.' != *s) && ((*s < '0') || (*s > '9')) ) {      return PR_FAILURE;    }    /* No two consecutive periods */    if( ('.' == *s) && ('.' == s[1]) ) {      return PR_FAILURE;    }  }  /*   * The last character isn't a period   */  if( '.' == *--s ) {    return PR_FAILURE;  }  return PR_SUCCESS;}static PRUint32oid_encode_number(  PRUint32 n,  PRUint8 *dp,  PRUint32 nb){  PRUint32 a[5];  PRUint32 i;  PRUint32 rv;  a[0] = (n >> 28) & 0x7f;  a[1] = (n >> 21) & 0x7f;  a[2] = (n >> 14) & 0x7f;  a[3] = (n >>  7) & 0x7f;  a[4] =  n        & 0x7f;  for( i = 0; i < 5; i++ ) {    if( 0 != a[i] ) {      break;    }  }  if( 5 == i ) {    i--;  }  rv = 5-i;  if( rv > nb ) {    return rv;  }  for( ; i < 4; i++ ) {    *dp = 0x80 | a[i];    dp++;  }  *dp = a[4];  return rv;}/* * oid_encode_huge * * This routine will convert a huge decimal number into the DER  * encoding for oid numbers.  It is not limited to numbers that will * fit into some wordsize, like oid_encode_number.  But it's not * necessarily very fast, either.  This is here in case some joker * throws us an ASCII oid like 1.2.3.99999999999999999999999999. */static PRUint32oid_encode_huge(  NSSUTF8 *s,  NSSUTF8 *e,  PRUint8 *dp,  PRUint32 nb){  PRUint32 slen = (e-s);  PRUint32 blen = (slen+1)/2;  PRUint8 *st = (PRUint8 *)NULL;  PRUint8 *bd = (PRUint8 *)NULL;  PRUint32 i;  PRUint32 bitno;  PRUint8 *last;  PRUint8 *first;  PRUint32 byteno;  PRUint8 mask;  /* We'll be munging the data, so duplicate it */  st = (PRUint8 *)nss_ZAlloc((NSSArena *)NULL, slen);  if( (PRUint8 *)NULL == st ) {    return 0;  }  /* Don't know ahead of time exactly how long we'll need */  bd = (PRUint8 *)nss_ZAlloc((NSSArena *)NULL, blen);  if( (PRUint8 *)NULL == bd ) {    (void)nss_ZFreeIf(st);    return 0;  }  /* Copy the original, and convert ASCII to numbers */  for( i = 0; i < slen; i++ ) {    st[i] = (PRUint8)(s[i] - '0');  }  last = &st[slen-1];  first = &st[0];  /*   * The way we create the binary version is by looking at it    * bit by bit.  Start with the least significant bit.  If the   * number is odd, set that bit.  Halve the number (with integer   * division), and go to the next least significant bit.  Keep    * going until the number goes to zero.   */  for( bitno = 0; ; bitno++ ) {    PRUint8 *d;    byteno = bitno/7;    mask = (PRUint8)(1 << (bitno%7));    /* Skip leading zeroes */    for( ; first < last; first ++ ) {      if( 0 != *first ) {        break;      }    }    /* Down to one number and it's a zero?  Done. */    if( (first == last) && (0 == *last) ) {      break;    }    /* Last digit is odd?  Set the bit */    if( *last & 1 ) {      bd[ byteno ] |= mask;    }    /*      * Divide the number in half.  This is just a matter     * of going from the least significant digit upwards,     * halving each one.  If any digit is odd (other than     * the last, which has already been handled), add five     * to the digit to its right.     */    *last /= 2;    for( d = &last[-1]; d >= first; d-- ) {      if( *d & 1 ) {        d[1] += 5;      }      *d /= 2;    }  }  /* Is there room to write the encoded data? */  if( (byteno+1) > nb ) {    return (byteno+1);  }  /* Trim any leading zero that crept in there */  for( ; byteno > 0; byteno-- ) {    if( 0 != bd[ byteno ] ) {      break;    }  }  /* Copy all but the last, marking the "continue" bit */  for( i = 0; i < byteno; i++ ) {    dp[i] = bd[ byteno-i ] | 0x80;  }  /* And the last with the "continue" bit clear */  dp[byteno] = bd[0];  (void)nss_ZFreeIf(bd);  (void)nss_ZFreeIf(st);  return (byteno+1);}/* * oid_encode_string * * This routine converts a dotted-number OID into a DER-encoded * one.  It assumes we've already sanity-checked the string. */extern const NSSError NSS_ERROR_INTERNAL_ERROR;static NSSOID *oid_encode_string(  NSSUTF8 *s){  PRUint32 nn = 0; /* number of numbers */  PRUint32 nb = 0; /* number of bytes (estimated) */  NSSUTF8 *t;  PRUint32 nd = 0; /* number of digits */  NSSOID *rv;  PRUint8 *dp;  PRUint32 a, b;  PRUint32 inc;  /* Dump any octothorpe */  if( '#' == *s ) {    s++;  }  /* Count up the bytes needed */  for( t = s; '\0' != *t; t++ ) {    if( '.' == *t ) {      nb += (nd+1)/2; /* errs on the big side */      nd = 0;      nn++;    } else {      nd++;    }  }  nb += (nd+1)/2;  nn++;  if( 1 == nn ) {    /*     * We have our own "denormalised" encoding for these,     * which is only used internally.     */    nb++;  }  /*    * Allocate.  Note that we don't use the oid_arena here.. this is   * because there really isn't a "free()" for stuff allocated out of   * arenas (at least with the current implementation), so this would   * keep using up memory each time a UTF8-encoded OID were added.   * If need be (if this is the first time this oid has been seen),   * we'll copy it.   */  rv = nss_ZNEW((NSSArena *)NULL, NSSOID);  if( (NSSOID *)NULL == rv ) {    return (NSSOID *)NULL;  }  rv->data.data = nss_ZAlloc((NSSArena *)NULL, nb);  if( (void *)NULL == rv->data.data ) {    (void)nss_ZFreeIf(rv);    return (NSSOID *)NULL;  }  dp = (PRUint8 *)rv->data.data;  a = atoi(s);  if( 1 == nn ) {    dp[0] = '\x80';    inc = oid_encode_number(a, &dp[1], nb-1);    if( inc >= nb ) {      goto loser;    }  } else {    for( t = s; '.' != *t; t++ ) {      ;    }    t++;    b = atoi(t);    inc = oid_encode_number(a*40+b, dp, nb);    if( inc > nb ) {      goto loser;    }    dp += inc;    nb -= inc;    nn -= 2;    while( nn-- > 0 ) {      NSSUTF8 *u;      for( ; '.' != *t; t++ ) {        ;      }      t++;      for( u = t; ('\0' != *u) && ('.' != *u); u++ ) {        ;      }      if( (u-t > 9) ) {        /* In the billions.  Rats. */        inc = oid_encode_huge(t, u, dp, nb);      } else {        b = atoi(t);        inc = oid_encode_number(b, dp, nb);      }      if( inc > nb ) {        goto loser;      }      dp += inc;      nb -= inc;    }  }  return rv; loser:  nss_SetError(NSS_ERROR_INTERNAL_ERROR);  return (NSSOID *)NULL;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?