andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: /* andre@0: * certhtml.c --- convert a cert to html andre@0: */ andre@0: andre@0: #include "seccomon.h" andre@0: #include "secitem.h" andre@0: #include "sechash.h" andre@0: #include "cert.h" andre@0: #include "keyhi.h" andre@0: #include "secder.h" andre@0: #include "prprf.h" andre@0: #include "secport.h" andre@0: #include "secasn1.h" andre@0: #include "pk11func.h" andre@0: andre@0: static char *hex = "0123456789ABCDEF"; andre@0: andre@0: /* andre@0: ** Convert a der-encoded integer to a hex printable string form andre@0: */ andre@0: char *CERT_Hexify (SECItem *i, int do_colon) andre@0: { andre@0: unsigned char *cp, *end; andre@0: char *rv, *o; andre@0: andre@0: if (!i->len) { andre@0: return PORT_Strdup("00"); andre@0: } andre@0: andre@0: rv = o = (char*) PORT_Alloc(i->len * 3); andre@0: if (!rv) return rv; andre@0: andre@0: cp = i->data; andre@0: end = cp + i->len; andre@0: while (cp < end) { andre@0: unsigned char ch = *cp++; andre@0: *o++ = hex[(ch >> 4) & 0xf]; andre@0: *o++ = hex[ch & 0xf]; andre@0: if (cp != end) { andre@0: if (do_colon) { andre@0: *o++ = ':'; andre@0: } andre@0: } andre@0: } andre@0: *o = 0; /* Null terminate the string */ andre@0: return rv; andre@0: } andre@0: andre@0: #define BREAK "
" andre@0: #define BREAKLEN 4 andre@0: #define COMMA ", " andre@0: #define COMMALEN 2 andre@0: andre@0: #define MAX_OUS 20 andre@0: #define MAX_DC MAX_OUS andre@0: andre@0: andre@0: char *CERT_FormatName (CERTName *name) andre@0: { andre@0: CERTRDN** rdns; andre@0: CERTRDN * rdn; andre@0: CERTAVA** avas; andre@0: CERTAVA* ava; andre@0: char * buf = 0; andre@0: char * tmpbuf = 0; andre@0: SECItem * cn = 0; andre@0: SECItem * email = 0; andre@0: SECItem * org = 0; andre@0: SECItem * loc = 0; andre@0: SECItem * state = 0; andre@0: SECItem * country = 0; andre@0: SECItem * dq = 0; andre@0: andre@0: unsigned len = 0; andre@0: int tag; andre@0: int i; andre@0: int ou_count = 0; andre@0: int dc_count = 0; andre@0: PRBool first; andre@0: SECItem * orgunit[MAX_OUS]; andre@0: SECItem * dc[MAX_DC]; andre@0: andre@0: /* Loop over name components and gather the interesting ones */ andre@0: rdns = name->rdns; andre@0: while ((rdn = *rdns++) != 0) { andre@0: avas = rdn->avas; andre@0: while ((ava = *avas++) != 0) { andre@0: tag = CERT_GetAVATag(ava); andre@0: switch(tag) { andre@0: case SEC_OID_AVA_COMMON_NAME: andre@0: if (cn) { andre@0: break; andre@0: } andre@0: cn = CERT_DecodeAVAValue(&ava->value); andre@0: if (!cn) { andre@0: goto loser; andre@0: } andre@0: len += cn->len; andre@0: break; andre@0: case SEC_OID_AVA_COUNTRY_NAME: andre@0: if (country) { andre@0: break; andre@0: } andre@0: country = CERT_DecodeAVAValue(&ava->value); andre@0: if (!country) { andre@0: goto loser; andre@0: } andre@0: len += country->len; andre@0: break; andre@0: case SEC_OID_AVA_LOCALITY: andre@0: if (loc) { andre@0: break; andre@0: } andre@0: loc = CERT_DecodeAVAValue(&ava->value); andre@0: if (!loc) { andre@0: goto loser; andre@0: } andre@0: len += loc->len; andre@0: break; andre@0: case SEC_OID_AVA_STATE_OR_PROVINCE: andre@0: if (state) { andre@0: break; andre@0: } andre@0: state = CERT_DecodeAVAValue(&ava->value); andre@0: if (!state) { andre@0: goto loser; andre@0: } andre@0: len += state->len; andre@0: break; andre@0: case SEC_OID_AVA_ORGANIZATION_NAME: andre@0: if (org) { andre@0: break; andre@0: } andre@0: org = CERT_DecodeAVAValue(&ava->value); andre@0: if (!org) { andre@0: goto loser; andre@0: } andre@0: len += org->len; andre@0: break; andre@0: case SEC_OID_AVA_DN_QUALIFIER: andre@0: if (dq) { andre@0: break; andre@0: } andre@0: dq = CERT_DecodeAVAValue(&ava->value); andre@0: if (!dq) { andre@0: goto loser; andre@0: } andre@0: len += dq->len; andre@0: break; andre@0: case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: andre@0: if (ou_count < MAX_OUS) { andre@0: orgunit[ou_count] = CERT_DecodeAVAValue(&ava->value); andre@0: if (!orgunit[ou_count]) { andre@0: goto loser; andre@0: } andre@0: len += orgunit[ou_count++]->len; andre@0: } andre@0: break; andre@0: case SEC_OID_AVA_DC: andre@0: if (dc_count < MAX_DC) { andre@0: dc[dc_count] = CERT_DecodeAVAValue(&ava->value); andre@0: if (!dc[dc_count]) { andre@0: goto loser; andre@0: } andre@0: len += dc[dc_count++]->len; andre@0: } andre@0: break; andre@0: case SEC_OID_PKCS9_EMAIL_ADDRESS: andre@0: case SEC_OID_RFC1274_MAIL: andre@0: if (email) { andre@0: break; andre@0: } andre@0: email = CERT_DecodeAVAValue(&ava->value); andre@0: if (!email) { andre@0: goto loser; andre@0: } andre@0: len += email->len; andre@0: break; andre@0: default: andre@0: break; andre@0: } andre@0: } andre@0: } andre@0: andre@0: /* XXX - add some for formatting */ andre@0: len += 128; andre@0: andre@0: /* allocate buffer */ andre@0: buf = (char *)PORT_Alloc(len); andre@0: if ( !buf ) { andre@0: goto loser; andre@0: } andre@0: andre@0: tmpbuf = buf; andre@0: andre@0: if ( cn ) { andre@0: PORT_Memcpy(tmpbuf, cn->data, cn->len); andre@0: tmpbuf += cn->len; andre@0: PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); andre@0: tmpbuf += BREAKLEN; andre@0: } andre@0: if ( email ) { andre@0: PORT_Memcpy(tmpbuf, email->data, email->len); andre@0: tmpbuf += ( email->len ); andre@0: PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); andre@0: tmpbuf += BREAKLEN; andre@0: } andre@0: for (i=ou_count-1; i >= 0; i--) { andre@0: PORT_Memcpy(tmpbuf, orgunit[i]->data, orgunit[i]->len); andre@0: tmpbuf += ( orgunit[i]->len ); andre@0: PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); andre@0: tmpbuf += BREAKLEN; andre@0: } andre@0: if ( dq ) { andre@0: PORT_Memcpy(tmpbuf, dq->data, dq->len); andre@0: tmpbuf += ( dq->len ); andre@0: PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); andre@0: tmpbuf += BREAKLEN; andre@0: } andre@0: if ( org ) { andre@0: PORT_Memcpy(tmpbuf, org->data, org->len); andre@0: tmpbuf += ( org->len ); andre@0: PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); andre@0: tmpbuf += BREAKLEN; andre@0: } andre@0: for (i=dc_count-1; i >= 0; i--) { andre@0: PORT_Memcpy(tmpbuf, dc[i]->data, dc[i]->len); andre@0: tmpbuf += ( dc[i]->len ); andre@0: PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); andre@0: tmpbuf += BREAKLEN; andre@0: } andre@0: first = PR_TRUE; andre@0: if ( loc ) { andre@0: PORT_Memcpy(tmpbuf, loc->data, loc->len); andre@0: tmpbuf += ( loc->len ); andre@0: first = PR_FALSE; andre@0: } andre@0: if ( state ) { andre@0: if ( !first ) { andre@0: PORT_Memcpy(tmpbuf, COMMA, COMMALEN); andre@0: tmpbuf += COMMALEN; andre@0: } andre@0: PORT_Memcpy(tmpbuf, state->data, state->len); andre@0: tmpbuf += ( state->len ); andre@0: first = PR_FALSE; andre@0: } andre@0: if ( country ) { andre@0: if ( !first ) { andre@0: PORT_Memcpy(tmpbuf, COMMA, COMMALEN); andre@0: tmpbuf += COMMALEN; andre@0: } andre@0: PORT_Memcpy(tmpbuf, country->data, country->len); andre@0: tmpbuf += ( country->len ); andre@0: first = PR_FALSE; andre@0: } andre@0: if ( !first ) { andre@0: PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); andre@0: tmpbuf += BREAKLEN; andre@0: } andre@0: andre@0: *tmpbuf = 0; andre@0: andre@0: /* fall through and clean */ andre@0: loser: andre@0: if ( cn ) { andre@0: SECITEM_FreeItem(cn, PR_TRUE); andre@0: } andre@0: if ( email ) { andre@0: SECITEM_FreeItem(email, PR_TRUE); andre@0: } andre@0: for (i=ou_count-1; i >= 0; i--) { andre@0: SECITEM_FreeItem(orgunit[i], PR_TRUE); andre@0: } andre@0: if ( dq ) { andre@0: SECITEM_FreeItem(dq, PR_TRUE); andre@0: } andre@0: if ( org ) { andre@0: SECITEM_FreeItem(org, PR_TRUE); andre@0: } andre@0: for (i=dc_count-1; i >= 0; i--) { andre@0: SECITEM_FreeItem(dc[i], PR_TRUE); andre@0: } andre@0: if ( loc ) { andre@0: SECITEM_FreeItem(loc, PR_TRUE); andre@0: } andre@0: if ( state ) { andre@0: SECITEM_FreeItem(state, PR_TRUE); andre@0: } andre@0: if ( country ) { andre@0: SECITEM_FreeItem(country, PR_TRUE); andre@0: } andre@0: andre@0: return(buf); andre@0: } andre@0: