Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | /* |
michael@0 | 6 | * certhtml.c --- convert a cert to html |
michael@0 | 7 | */ |
michael@0 | 8 | |
michael@0 | 9 | #include "seccomon.h" |
michael@0 | 10 | #include "secitem.h" |
michael@0 | 11 | #include "sechash.h" |
michael@0 | 12 | #include "cert.h" |
michael@0 | 13 | #include "keyhi.h" |
michael@0 | 14 | #include "secder.h" |
michael@0 | 15 | #include "prprf.h" |
michael@0 | 16 | #include "secport.h" |
michael@0 | 17 | #include "secasn1.h" |
michael@0 | 18 | #include "pk11func.h" |
michael@0 | 19 | |
michael@0 | 20 | static char *hex = "0123456789ABCDEF"; |
michael@0 | 21 | |
michael@0 | 22 | /* |
michael@0 | 23 | ** Convert a der-encoded integer to a hex printable string form |
michael@0 | 24 | */ |
michael@0 | 25 | char *CERT_Hexify (SECItem *i, int do_colon) |
michael@0 | 26 | { |
michael@0 | 27 | unsigned char *cp, *end; |
michael@0 | 28 | char *rv, *o; |
michael@0 | 29 | |
michael@0 | 30 | if (!i->len) { |
michael@0 | 31 | return PORT_Strdup("00"); |
michael@0 | 32 | } |
michael@0 | 33 | |
michael@0 | 34 | rv = o = (char*) PORT_Alloc(i->len * 3); |
michael@0 | 35 | if (!rv) return rv; |
michael@0 | 36 | |
michael@0 | 37 | cp = i->data; |
michael@0 | 38 | end = cp + i->len; |
michael@0 | 39 | while (cp < end) { |
michael@0 | 40 | unsigned char ch = *cp++; |
michael@0 | 41 | *o++ = hex[(ch >> 4) & 0xf]; |
michael@0 | 42 | *o++ = hex[ch & 0xf]; |
michael@0 | 43 | if (cp != end) { |
michael@0 | 44 | if (do_colon) { |
michael@0 | 45 | *o++ = ':'; |
michael@0 | 46 | } |
michael@0 | 47 | } |
michael@0 | 48 | } |
michael@0 | 49 | *o = 0; /* Null terminate the string */ |
michael@0 | 50 | return rv; |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | #define BREAK "<br>" |
michael@0 | 54 | #define BREAKLEN 4 |
michael@0 | 55 | #define COMMA ", " |
michael@0 | 56 | #define COMMALEN 2 |
michael@0 | 57 | |
michael@0 | 58 | #define MAX_OUS 20 |
michael@0 | 59 | #define MAX_DC MAX_OUS |
michael@0 | 60 | |
michael@0 | 61 | |
michael@0 | 62 | char *CERT_FormatName (CERTName *name) |
michael@0 | 63 | { |
michael@0 | 64 | CERTRDN** rdns; |
michael@0 | 65 | CERTRDN * rdn; |
michael@0 | 66 | CERTAVA** avas; |
michael@0 | 67 | CERTAVA* ava; |
michael@0 | 68 | char * buf = 0; |
michael@0 | 69 | char * tmpbuf = 0; |
michael@0 | 70 | SECItem * cn = 0; |
michael@0 | 71 | SECItem * email = 0; |
michael@0 | 72 | SECItem * org = 0; |
michael@0 | 73 | SECItem * loc = 0; |
michael@0 | 74 | SECItem * state = 0; |
michael@0 | 75 | SECItem * country = 0; |
michael@0 | 76 | SECItem * dq = 0; |
michael@0 | 77 | |
michael@0 | 78 | unsigned len = 0; |
michael@0 | 79 | int tag; |
michael@0 | 80 | int i; |
michael@0 | 81 | int ou_count = 0; |
michael@0 | 82 | int dc_count = 0; |
michael@0 | 83 | PRBool first; |
michael@0 | 84 | SECItem * orgunit[MAX_OUS]; |
michael@0 | 85 | SECItem * dc[MAX_DC]; |
michael@0 | 86 | |
michael@0 | 87 | /* Loop over name components and gather the interesting ones */ |
michael@0 | 88 | rdns = name->rdns; |
michael@0 | 89 | while ((rdn = *rdns++) != 0) { |
michael@0 | 90 | avas = rdn->avas; |
michael@0 | 91 | while ((ava = *avas++) != 0) { |
michael@0 | 92 | tag = CERT_GetAVATag(ava); |
michael@0 | 93 | switch(tag) { |
michael@0 | 94 | case SEC_OID_AVA_COMMON_NAME: |
michael@0 | 95 | if (cn) { |
michael@0 | 96 | break; |
michael@0 | 97 | } |
michael@0 | 98 | cn = CERT_DecodeAVAValue(&ava->value); |
michael@0 | 99 | if (!cn) { |
michael@0 | 100 | goto loser; |
michael@0 | 101 | } |
michael@0 | 102 | len += cn->len; |
michael@0 | 103 | break; |
michael@0 | 104 | case SEC_OID_AVA_COUNTRY_NAME: |
michael@0 | 105 | if (country) { |
michael@0 | 106 | break; |
michael@0 | 107 | } |
michael@0 | 108 | country = CERT_DecodeAVAValue(&ava->value); |
michael@0 | 109 | if (!country) { |
michael@0 | 110 | goto loser; |
michael@0 | 111 | } |
michael@0 | 112 | len += country->len; |
michael@0 | 113 | break; |
michael@0 | 114 | case SEC_OID_AVA_LOCALITY: |
michael@0 | 115 | if (loc) { |
michael@0 | 116 | break; |
michael@0 | 117 | } |
michael@0 | 118 | loc = CERT_DecodeAVAValue(&ava->value); |
michael@0 | 119 | if (!loc) { |
michael@0 | 120 | goto loser; |
michael@0 | 121 | } |
michael@0 | 122 | len += loc->len; |
michael@0 | 123 | break; |
michael@0 | 124 | case SEC_OID_AVA_STATE_OR_PROVINCE: |
michael@0 | 125 | if (state) { |
michael@0 | 126 | break; |
michael@0 | 127 | } |
michael@0 | 128 | state = CERT_DecodeAVAValue(&ava->value); |
michael@0 | 129 | if (!state) { |
michael@0 | 130 | goto loser; |
michael@0 | 131 | } |
michael@0 | 132 | len += state->len; |
michael@0 | 133 | break; |
michael@0 | 134 | case SEC_OID_AVA_ORGANIZATION_NAME: |
michael@0 | 135 | if (org) { |
michael@0 | 136 | break; |
michael@0 | 137 | } |
michael@0 | 138 | org = CERT_DecodeAVAValue(&ava->value); |
michael@0 | 139 | if (!org) { |
michael@0 | 140 | goto loser; |
michael@0 | 141 | } |
michael@0 | 142 | len += org->len; |
michael@0 | 143 | break; |
michael@0 | 144 | case SEC_OID_AVA_DN_QUALIFIER: |
michael@0 | 145 | if (dq) { |
michael@0 | 146 | break; |
michael@0 | 147 | } |
michael@0 | 148 | dq = CERT_DecodeAVAValue(&ava->value); |
michael@0 | 149 | if (!dq) { |
michael@0 | 150 | goto loser; |
michael@0 | 151 | } |
michael@0 | 152 | len += dq->len; |
michael@0 | 153 | break; |
michael@0 | 154 | case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: |
michael@0 | 155 | if (ou_count < MAX_OUS) { |
michael@0 | 156 | orgunit[ou_count] = CERT_DecodeAVAValue(&ava->value); |
michael@0 | 157 | if (!orgunit[ou_count]) { |
michael@0 | 158 | goto loser; |
michael@0 | 159 | } |
michael@0 | 160 | len += orgunit[ou_count++]->len; |
michael@0 | 161 | } |
michael@0 | 162 | break; |
michael@0 | 163 | case SEC_OID_AVA_DC: |
michael@0 | 164 | if (dc_count < MAX_DC) { |
michael@0 | 165 | dc[dc_count] = CERT_DecodeAVAValue(&ava->value); |
michael@0 | 166 | if (!dc[dc_count]) { |
michael@0 | 167 | goto loser; |
michael@0 | 168 | } |
michael@0 | 169 | len += dc[dc_count++]->len; |
michael@0 | 170 | } |
michael@0 | 171 | break; |
michael@0 | 172 | case SEC_OID_PKCS9_EMAIL_ADDRESS: |
michael@0 | 173 | case SEC_OID_RFC1274_MAIL: |
michael@0 | 174 | if (email) { |
michael@0 | 175 | break; |
michael@0 | 176 | } |
michael@0 | 177 | email = CERT_DecodeAVAValue(&ava->value); |
michael@0 | 178 | if (!email) { |
michael@0 | 179 | goto loser; |
michael@0 | 180 | } |
michael@0 | 181 | len += email->len; |
michael@0 | 182 | break; |
michael@0 | 183 | default: |
michael@0 | 184 | break; |
michael@0 | 185 | } |
michael@0 | 186 | } |
michael@0 | 187 | } |
michael@0 | 188 | |
michael@0 | 189 | /* XXX - add some for formatting */ |
michael@0 | 190 | len += 128; |
michael@0 | 191 | |
michael@0 | 192 | /* allocate buffer */ |
michael@0 | 193 | buf = (char *)PORT_Alloc(len); |
michael@0 | 194 | if ( !buf ) { |
michael@0 | 195 | goto loser; |
michael@0 | 196 | } |
michael@0 | 197 | |
michael@0 | 198 | tmpbuf = buf; |
michael@0 | 199 | |
michael@0 | 200 | if ( cn ) { |
michael@0 | 201 | PORT_Memcpy(tmpbuf, cn->data, cn->len); |
michael@0 | 202 | tmpbuf += cn->len; |
michael@0 | 203 | PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); |
michael@0 | 204 | tmpbuf += BREAKLEN; |
michael@0 | 205 | } |
michael@0 | 206 | if ( email ) { |
michael@0 | 207 | PORT_Memcpy(tmpbuf, email->data, email->len); |
michael@0 | 208 | tmpbuf += ( email->len ); |
michael@0 | 209 | PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); |
michael@0 | 210 | tmpbuf += BREAKLEN; |
michael@0 | 211 | } |
michael@0 | 212 | for (i=ou_count-1; i >= 0; i--) { |
michael@0 | 213 | PORT_Memcpy(tmpbuf, orgunit[i]->data, orgunit[i]->len); |
michael@0 | 214 | tmpbuf += ( orgunit[i]->len ); |
michael@0 | 215 | PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); |
michael@0 | 216 | tmpbuf += BREAKLEN; |
michael@0 | 217 | } |
michael@0 | 218 | if ( dq ) { |
michael@0 | 219 | PORT_Memcpy(tmpbuf, dq->data, dq->len); |
michael@0 | 220 | tmpbuf += ( dq->len ); |
michael@0 | 221 | PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); |
michael@0 | 222 | tmpbuf += BREAKLEN; |
michael@0 | 223 | } |
michael@0 | 224 | if ( org ) { |
michael@0 | 225 | PORT_Memcpy(tmpbuf, org->data, org->len); |
michael@0 | 226 | tmpbuf += ( org->len ); |
michael@0 | 227 | PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); |
michael@0 | 228 | tmpbuf += BREAKLEN; |
michael@0 | 229 | } |
michael@0 | 230 | for (i=dc_count-1; i >= 0; i--) { |
michael@0 | 231 | PORT_Memcpy(tmpbuf, dc[i]->data, dc[i]->len); |
michael@0 | 232 | tmpbuf += ( dc[i]->len ); |
michael@0 | 233 | PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); |
michael@0 | 234 | tmpbuf += BREAKLEN; |
michael@0 | 235 | } |
michael@0 | 236 | first = PR_TRUE; |
michael@0 | 237 | if ( loc ) { |
michael@0 | 238 | PORT_Memcpy(tmpbuf, loc->data, loc->len); |
michael@0 | 239 | tmpbuf += ( loc->len ); |
michael@0 | 240 | first = PR_FALSE; |
michael@0 | 241 | } |
michael@0 | 242 | if ( state ) { |
michael@0 | 243 | if ( !first ) { |
michael@0 | 244 | PORT_Memcpy(tmpbuf, COMMA, COMMALEN); |
michael@0 | 245 | tmpbuf += COMMALEN; |
michael@0 | 246 | } |
michael@0 | 247 | PORT_Memcpy(tmpbuf, state->data, state->len); |
michael@0 | 248 | tmpbuf += ( state->len ); |
michael@0 | 249 | first = PR_FALSE; |
michael@0 | 250 | } |
michael@0 | 251 | if ( country ) { |
michael@0 | 252 | if ( !first ) { |
michael@0 | 253 | PORT_Memcpy(tmpbuf, COMMA, COMMALEN); |
michael@0 | 254 | tmpbuf += COMMALEN; |
michael@0 | 255 | } |
michael@0 | 256 | PORT_Memcpy(tmpbuf, country->data, country->len); |
michael@0 | 257 | tmpbuf += ( country->len ); |
michael@0 | 258 | first = PR_FALSE; |
michael@0 | 259 | } |
michael@0 | 260 | if ( !first ) { |
michael@0 | 261 | PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); |
michael@0 | 262 | tmpbuf += BREAKLEN; |
michael@0 | 263 | } |
michael@0 | 264 | |
michael@0 | 265 | *tmpbuf = 0; |
michael@0 | 266 | |
michael@0 | 267 | /* fall through and clean */ |
michael@0 | 268 | loser: |
michael@0 | 269 | if ( cn ) { |
michael@0 | 270 | SECITEM_FreeItem(cn, PR_TRUE); |
michael@0 | 271 | } |
michael@0 | 272 | if ( email ) { |
michael@0 | 273 | SECITEM_FreeItem(email, PR_TRUE); |
michael@0 | 274 | } |
michael@0 | 275 | for (i=ou_count-1; i >= 0; i--) { |
michael@0 | 276 | SECITEM_FreeItem(orgunit[i], PR_TRUE); |
michael@0 | 277 | } |
michael@0 | 278 | if ( dq ) { |
michael@0 | 279 | SECITEM_FreeItem(dq, PR_TRUE); |
michael@0 | 280 | } |
michael@0 | 281 | if ( org ) { |
michael@0 | 282 | SECITEM_FreeItem(org, PR_TRUE); |
michael@0 | 283 | } |
michael@0 | 284 | for (i=dc_count-1; i >= 0; i--) { |
michael@0 | 285 | SECITEM_FreeItem(dc[i], PR_TRUE); |
michael@0 | 286 | } |
michael@0 | 287 | if ( loc ) { |
michael@0 | 288 | SECITEM_FreeItem(loc, PR_TRUE); |
michael@0 | 289 | } |
michael@0 | 290 | if ( state ) { |
michael@0 | 291 | SECITEM_FreeItem(state, PR_TRUE); |
michael@0 | 292 | } |
michael@0 | 293 | if ( country ) { |
michael@0 | 294 | SECITEM_FreeItem(country, PR_TRUE); |
michael@0 | 295 | } |
michael@0 | 296 | |
michael@0 | 297 | return(buf); |
michael@0 | 298 | } |
michael@0 | 299 |