summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorian.mcgreer%sun.com <devnull@localhost>2002-12-04 18:31:04 +0000
committerian.mcgreer%sun.com <devnull@localhost>2002-12-04 18:31:04 +0000
commit1abc803ca8899f1c0c5a2872fc3d274382a881ae (patch)
tree0223c5eb801c08d40a372f8a92c4b432805160f1
parentde9516ee30f032a4692f869b285ef62c769f749a (diff)
downloadnss-hg-1abc803ca8899f1c0c5a2872fc3d274382a881ae.tar.gz
bug 39494, handle unknown attribute type conversion correctly
r/a=wtc
-rw-r--r--security/nss/lib/certdb/alg1485.c137
1 files changed, 129 insertions, 8 deletions
diff --git a/security/nss/lib/certdb/alg1485.c b/security/nss/lib/certdb/alg1485.c
index b5e71fb70..139e422eb 100644
--- a/security/nss/lib/certdb/alg1485.c
+++ b/security/nss/lib/certdb/alg1485.c
@@ -31,6 +31,7 @@
* GPL.
*/
+#include "prprf.h"
#include "cert.h"
#include "xconst.h"
#include "genname.h"
@@ -602,6 +603,116 @@ CERT_RFC1485_EscapeAndQuote(char *dst, int dstlen, char *src, int srclen)
return SECSuccess;
}
+/* convert an OID to dotted-decimal representation */
+static char *
+get_oid_string
+(
+ SECItem *oid
+)
+{
+ PRUint8 *end;
+ PRUint8 *d;
+ PRUint8 *e;
+ char *a;
+ char *b;
+
+ a = (char *)NULL;
+
+ /* d will point to the next sequence of bytes to decode */
+ d = (PRUint8 *)oid->data;
+ /* end points to one past the legitimate data */
+ end = &d[ oid->len ];
+
+ /*
+ * Check for our pseudo-encoded single-digit OIDs
+ */
+ if( (*d == 0x80) && (2 == oid->len) ) {
+ /* Funky encoding. The second byte is the number */
+ a = PR_smprintf("%lu", (PRUint32)d[1]);
+ if( (char *)NULL == a ) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return (char *)NULL;
+ }
+ return a;
+ }
+
+ for( ; d < end; d = &e[1] ) {
+
+ for( e = d; e < end; e++ ) {
+ if( 0 == (*e & 0x80) ) {
+ break;
+ }
+ }
+
+ if( ((e-d) > 4) || (((e-d) == 4) && (*d & 0x70)) ) {
+ /* More than a 32-bit number */
+ } else {
+ PRUint32 n = 0;
+
+ switch( e-d ) {
+ case 4:
+ n |= ((PRUint32)(e[-4] & 0x0f)) << 28;
+ case 3:
+ n |= ((PRUint32)(e[-3] & 0x7f)) << 21;
+ case 2:
+ n |= ((PRUint32)(e[-2] & 0x7f)) << 14;
+ case 1:
+ n |= ((PRUint32)(e[-1] & 0x7f)) << 7;
+ case 0:
+ n |= ((PRUint32)(e[-0] & 0x7f)) ;
+ }
+
+ if( (char *)NULL == a ) {
+ /* This is the first number.. decompose it */
+ PRUint32 one = PR_MIN(n/40, 2); /* never > 2 */
+ PRUint32 two = n - one * 40;
+
+ a = PR_smprintf("%lu.%lu", one, two);
+ if( (char *)NULL == a ) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return (char *)NULL;
+ }
+ } else {
+ b = PR_smprintf("%s.%lu", a, n);
+ if( (char *)NULL == b ) {
+ PR_smprintf_free(a);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return (char *)NULL;
+ }
+
+ PR_smprintf_free(a);
+ a = b;
+ }
+ }
+ }
+
+ return a;
+}
+
+/* convert DER-encoded hex to a string */
+static SECItem *
+get_hex_string(SECItem *data)
+{
+ SECItem *rv;
+ unsigned int i, j;
+ static const char hex[] = { "0123456789ABCDEF" };
+
+ /* '#' + 2 chars per octet + terminator */
+ rv = SECITEM_AllocItem(NULL, NULL, data->len*2 + 2);
+ if (!rv) {
+ return NULL;
+ }
+ rv->data[0] = '#';
+ rv->len = 1 + 2 * data->len;
+ for (i=0; i<data->len; i++) {
+ j = data->data[i];
+ rv->data[2*i+1] = hex[j >> 4];
+ rv->data[2*i+2] = hex[j & 15];
+ }
+ rv->data[rv->len] = 0;
+ return rv;
+}
+
static SECStatus
AppendAVA(char **bufp, unsigned *buflenp, CERTAVA *ava)
{
@@ -612,6 +723,7 @@ AppendAVA(char **bufp, unsigned *buflenp, CERTAVA *ava)
int tag;
SECStatus rv;
SECItem *avaValue = NULL;
+ char *unknownTag = NULL;
tag = CERT_GetAVATag(ava);
switch (tag) {
@@ -660,28 +772,37 @@ AppendAVA(char **bufp, unsigned *buflenp, CERTAVA *ava)
maxLen = 256;
break;
default:
-#if 0
- PORT_SetError(SEC_ERROR_INVALID_AVA);
- return SECFailure;
-#else
- rv = AppendStr(bufp, buflenp, "ERR=Unknown AVA");
- return rv;
-#endif
+ /* handle unknown attribute types per RFC 2253 */
+ tagName = unknownTag = get_oid_string(&ava->type);
+ maxLen = 256;
+ break;
}
avaValue = CERT_DecodeAVAValue(&ava->value);
if(!avaValue) {
- return SECFailure;
+ /* the attribute value is not recognized, get the hex value */
+ avaValue = get_hex_string(&ava->value);
+ if(!avaValue) {
+ if (unknownTag) PR_smprintf_free(unknownTag);
+ return SECFailure;
+ }
}
/* Check value length */
if (avaValue->len > maxLen) {
+ if (unknownTag) PR_smprintf_free(unknownTag);
PORT_SetError(SEC_ERROR_INVALID_AVA);
return SECFailure;
}
len = PORT_Strlen(tagName);
+ if (len+1 > sizeof(tmpBuf)) {
+ if (unknownTag) PR_smprintf_free(unknownTag);
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ return SECFailure;
+ }
PORT_Memcpy(tmpBuf, tagName, len);
+ if (unknownTag) PR_smprintf_free(unknownTag);
tmpBuf[len++] = '=';
/* escape and quote as necessary */