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 + -
显示快捷键?