1 /* vi: set sw=4 ts=4:
2 *
3 * Copyright (C) 2001 - 2011 Christian Hohnstaedt.
4 *
5 * All rights reserved.
6 */
7
8 #include "x509v3ext.h"
9 #include "x509name.h"
10 #include "asn1int.h"
11 #include "func.h"
12 #include "exception.h"
13 #include <openssl/x509v3.h>
14 #include <openssl/stack.h>
15 #include <QStringList>
16 #include <QDebug>
17 #include "base.h"
18 #include "BioByteArray.h"
19
x509v3ext()20 x509v3ext::x509v3ext()
21 {
22 ext = X509_EXTENSION_new();
23 }
24
x509v3ext(const X509_EXTENSION * n)25 x509v3ext::x509v3ext(const X509_EXTENSION *n)
26 {
27 ext = X509_EXTENSION_dup((X509_EXTENSION *)n);
28 }
29
x509v3ext(const x509v3ext & n)30 x509v3ext::x509v3ext(const x509v3ext &n)
31 {
32 ASN1_OCTET_STRING *str = n.getData();
33 ext = X509_EXTENSION_new();
34 if (str && str->length)
35 set(n.ext);
36 }
37
~x509v3ext()38 x509v3ext::~x509v3ext()
39 {
40 X509_EXTENSION_free(ext);
41 }
42
set(const X509_EXTENSION * n)43 x509v3ext &x509v3ext::set(const X509_EXTENSION *n)
44 {
45 if (ext != NULL)
46 X509_EXTENSION_free(ext);
47 ext = X509_EXTENSION_dup((X509_EXTENSION *)n);
48 return *this;
49 }
50
create(int nid,const QString & et,X509V3_CTX * ctx)51 x509v3ext &x509v3ext::create(int nid, const QString &et, X509V3_CTX *ctx)
52 {
53 if (ext) {
54 X509_EXTENSION_free(ext);
55 ext = NULL;
56 }
57 if (!et.isEmpty()) {
58 QString etext = et;
59 if (et.contains("DNS:copycn") && ctx && ctx->subject_cert &&
60 nid == NID_subject_alt_name)
61 {
62 x509name xn(X509_get_subject_name(ctx->subject_cert));
63 QString cn = xn.getEntryByNid(NID_commonName);
64 if (!cn.isEmpty())
65 etext.replace(QString("DNS:copycn"),
66 QString("DNS:%1").arg(cn));
67 }
68 QByteArray ba = etext.toLocal8Bit();
69 ext = X509V3_EXT_conf_nid(NULL, ctx, nid, ba.data());
70 }
71 if (!ext)
72 ext = X509_EXTENSION_new();
73 else {
74 if (ctx && ctx->subject_cert) {
75 X509_add_ext(ctx->subject_cert, ext, -1);
76 }
77 }
78 return *this;
79 }
80
create_ia5(int nid,const QString & et,X509V3_CTX * ctx)81 x509v3ext &x509v3ext::create_ia5(int nid, const QString &et, X509V3_CTX *ctx)
82 {
83 QByteArray ba = et.toLocal8Bit();
84 for (int i=0; i<ba.size(); i++) {
85 if (ba[i] & 0x80)
86 throw errorEx(QObject::tr("String '%1' for '%2' contains invalid characters").arg(et).arg(OBJ_nid2ln(nid)));
87 }
88 return create(nid, et, ctx);
89 }
90
object() const91 const ASN1_OBJECT *x509v3ext::object() const
92 {
93 ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext);
94 try {
95 openssl_error();
96 } catch (errorEx e) {
97 return NULL;
98 }
99 return obj;
100 }
101
nid() const102 int x509v3ext::nid() const
103 {
104 const ASN1_OBJECT *obj = object();
105 if (!obj)
106 return NID_undef;
107 int nid = OBJ_obj2nid(obj);
108 if (nid == NID_undef) {
109 QString o = OBJ_obj2QString(obj, 1);
110 if (!o.isEmpty())
111 nid = OBJ_create(CCHAR(o), CCHAR(o), CCHAR(o));
112 }
113 return nid;
114 }
115
d2i() const116 void *x509v3ext::d2i() const
117 {
118 void *r = X509V3_EXT_d2i(ext);
119 ign_openssl_error();
120 return r;
121 }
122
operator =(const x509v3ext & x)123 x509v3ext &x509v3ext::operator = (const x509v3ext &x)
124 {
125 set(x.ext);
126 return *this;
127 }
128
getObject() const129 QString x509v3ext::getObject() const
130 {
131 const ASN1_OBJECT *obj = object();
132 return obj ? OBJ_obj2QString(obj) : QString("<ERROR>");
133 }
134
getCritical() const135 int x509v3ext::getCritical() const
136 {
137 return X509_EXTENSION_get_critical(ext);
138 }
139
getData() const140 ASN1_OCTET_STRING *x509v3ext::getData() const
141 {
142 return X509_EXTENSION_get_data(ext);
143 }
144
getValue() const145 QString x509v3ext::getValue() const
146 {
147 BioByteArray bba;
148 int ret = X509V3_EXT_print(bba, ext, X509V3_EXT_DEFAULT, 0);
149 if (ign_openssl_error() || !ret)
150 ret = ASN1_STRING_print(bba, (ASN1_STRING *)getData());
151 if (ign_openssl_error() || !ret)
152 return QString();
153 return bba.qstring().trimmed();
154 }
155
getHtmlValue() const156 QString x509v3ext::getHtmlValue() const
157 {
158 QString text = getValue();
159 text.replace(QRegExp("&"), "&");
160 text.replace(QRegExp("<"), "<");
161 text.replace(QRegExp(">"), ">");
162 text.replace(QRegExp("\n"), "<br>\n");
163 return text;
164 }
165
getConsoleValue(const QString & indent) const166 QString x509v3ext::getConsoleValue(const QString &indent) const
167 {
168 QString text = getValue();
169 text.replace(QRegExp("\n"), QString("\n") + indent);
170 return text;
171 }
172
vlist2Section(QStringList vlist,QString tag,QString * sect)173 static QString vlist2Section(QStringList vlist, QString tag, QString *sect)
174 {
175 /* Check for commas in the text */
176 if (!vlist.join("").contains(","))
177 return vlist.join(", ");
178
179 *sect += QString("\n[%1_sect]\n").arg(tag);
180
181 for (int i=0; i<vlist.count(); i++) {
182 QString s = vlist[i];
183 int eq = s.indexOf(":");
184 *sect += QString("%1.%2=%3\n").arg(s.left(eq)).
185 arg(i).arg(s.mid(eq+1));
186 }
187 return QString("@%1_sect\n").arg(tag);
188 }
189
obj2SnOid(const ASN1_OBJECT * a)190 static QString obj2SnOid(const ASN1_OBJECT *a)
191 {
192 QString obj;
193 int nid = OBJ_obj2nid(a);
194
195 if (nid == NID_undef)
196 obj = OBJ_obj2QString(a);
197 else
198 obj = OBJ_nid2sn(nid);
199
200 return obj;
201 }
202
asn1Type2Name(int type)203 static const char *asn1Type2Name(int type)
204 {
205 #define ASN1_GEN_STR(x,y) { x,y }
206 struct {
207 const char *strnam;
208 int tag;
209 } tags[] = {
210 ASN1_GEN_STR("BOOL", V_ASN1_BOOLEAN),
211 ASN1_GEN_STR("NULL", V_ASN1_NULL),
212 ASN1_GEN_STR("INT", V_ASN1_INTEGER),
213 ASN1_GEN_STR("ENUM", V_ASN1_ENUMERATED),
214 ASN1_GEN_STR("OID", V_ASN1_OBJECT),
215 ASN1_GEN_STR("UTC", V_ASN1_UTCTIME),
216 ASN1_GEN_STR("GENTIME", V_ASN1_GENERALIZEDTIME),
217 ASN1_GEN_STR("OCT", V_ASN1_OCTET_STRING),
218 ASN1_GEN_STR("BITSTR", V_ASN1_BIT_STRING),
219 ASN1_GEN_STR("UNIV", V_ASN1_UNIVERSALSTRING),
220 ASN1_GEN_STR("IA5", V_ASN1_IA5STRING),
221 ASN1_GEN_STR("UTF8", V_ASN1_UTF8STRING),
222 ASN1_GEN_STR("BMP", V_ASN1_BMPSTRING),
223 ASN1_GEN_STR("VISIBLE", V_ASN1_VISIBLESTRING),
224 ASN1_GEN_STR("PRINTABLE", V_ASN1_PRINTABLESTRING),
225 ASN1_GEN_STR("T61", V_ASN1_T61STRING),
226 ASN1_GEN_STR("GENSTR", V_ASN1_GENERALSTRING),
227 ASN1_GEN_STR("NUMERIC", V_ASN1_NUMERICSTRING),
228 };
229 for (unsigned i=0; i< ARRAY_SIZE(tags); i++) {
230 if (tags[i].tag == type)
231 return tags[i].strnam;
232 }
233 return "UNKNOWN";
234 }
235
asn1TypePrintable(int type)236 static bool asn1TypePrintable(int type)
237 {
238 switch (type) {
239 case V_ASN1_IA5STRING:
240 case V_ASN1_UTF8STRING:
241 case V_ASN1_BMPSTRING:
242 case V_ASN1_VISIBLESTRING:
243 case V_ASN1_PRINTABLESTRING:
244 case V_ASN1_T61STRING:
245 case V_ASN1_GENERALSTRING:
246 return true;
247 }
248 return false;
249 }
250
ipv6_from_binary(const unsigned char * p)251 static QString ipv6_from_binary(const unsigned char *p)
252 {
253 QString ip;
254 int i, skip =0, skiplen = 0, skippos =0;
255
256 /* find largest gap */
257 for (i = 0; i < 17; i += 2) {
258 if (i==16 || (p[i] | p[i +1])) {
259 if (skiplen < skip) {
260 skiplen = skip;
261 skippos = i - skip;
262 }
263 skip = 0;
264 } else {
265 skip += 2;
266 }
267 }
268 for (i = 0, skip = 0; i < 16; i += 2) {
269 int x = p[i] << 8 | p[i+1];
270 skip += skippos == i;
271 switch (!x*4 + skip) {
272 case 5: // skip first 0
273 skip = 2;
274 ip += ":";
275 case 6: // skip next 0
276 break;
277 default: // no reduction
278 skip = 0;
279 ip += QString("%1%2").arg(i? ":" : "").arg(x,0,16);
280 }
281 }
282 if (skip == 2)
283 ip += ":";
284 return ip;
285 }
286
287 static bool
genName2conf(GENERAL_NAME * gen,QString tag,QString * single,QString * sect)288 genName2conf(GENERAL_NAME *gen, QString tag, QString *single, QString *sect)
289 {
290 unsigned char *p;
291 QString ret;
292
293 switch (gen->type) {
294 case GEN_EMAIL: ret = "email:%1"; break;
295 case GEN_DNS: ret = "DNS:%1"; break;
296 case GEN_URI: ret = "URI:%1"; break;
297
298 case GEN_DIRNAME: {
299 tag += "_dirname";
300 x509name xn(gen->d.dirn);
301 *sect += QString("\n[%1]\n"). arg(tag);
302 *sect += xn.taggedValues();
303 *single = QString("dirName:") + tag;
304 return true;
305 }
306 case GEN_IPADD:
307 p = gen->d.ip->data;
308 if (gen->d.ip->length == 4) {
309 *single = QString("IP:%1.%2.%3.%4").
310 arg(p[0]).arg(p[1]).arg(p[2]).arg(p[3]);
311 return true;
312 } else if(gen->d.ip->length == 8) {
313 *single = QString("IP:%1.%2.%3.%4/%5.%6.%7.%8").
314 arg(p[0]).arg(p[1]).arg(p[2]).arg(p[3]).
315 arg(p[4]).arg(p[5]).arg(p[6]).arg(p[7]);
316 return true;
317 } else if(gen->d.ip->length == 16) {
318 *single = "IP:" + ipv6_from_binary(gen->d.ip->data);
319 return true;
320 } else if(gen->d.ip->length == 32) {
321 *single = "IP:" + ipv6_from_binary(gen->d.ip->data) +
322 "/" + ipv6_from_binary(gen->d.ip->data +16);
323 return true;
324 }
325 return false;
326
327 case GEN_RID:
328 *single = QString("RID:%1").
329 arg(obj2SnOid(gen->d.rid));
330 return true;
331 case GEN_OTHERNAME: {
332 int type = gen->d.otherName->value->type;
333 ASN1_STRING *a;
334 a = gen->d.otherName->value->value.asn1_string;
335 if (asn1TypePrintable(type)) {
336 *single = QString("otherName:%1;%2:%3").
337 arg(obj2SnOid(gen->d.otherName->type_id)).
338 arg(asn1Type2Name(type)).
339 arg(asn1ToQString(a, true));
340 } else {
341 *single = QString("otherName:%1;FORMAT:HEX,%2").
342 arg(obj2SnOid(gen->d.otherName->type_id)).
343 arg(asn1Type2Name(type));
344 for (int i=0; i<a->length; i++) {
345 *single += QString(":%1").
346 arg((int)(a->data[i]), 2, 16, QChar('0'));
347 }
348 }
349 return true;
350 }
351 default:
352 return false;
353 }
354 if (!ret.isEmpty())
355 *single = ret.arg(asn1ToQString(gen->d.ia5, true));
356 return true;
357 }
358
genNameStack2conf(STACK_OF (GENERAL_NAME)* gens,QString tag,QString * single,QString * sect)359 static bool genNameStack2conf(STACK_OF(GENERAL_NAME) *gens, QString tag,
360 QString *single, QString *sect)
361 {
362 int i;
363 QStringList sl;
364 for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
365 QString one;
366 if (!genName2conf(sk_GENERAL_NAME_value(gens, i),
367 QString("%1_%2").arg(tag).arg(i), &one, sect))
368 {
369 return false;
370 }
371 sl << one;
372 }
373 *single = vlist2Section(sl, tag, sect);
374 return true;
375 }
376
parse_critical() const377 QString x509v3ext::parse_critical() const
378 {
379 return QString(getCritical() ? "critical," : "");
380 }
381
382 #define TEXTS (\
383 B_ASN1_TIME | B_ASN1_DIRECTORYSTRING | B_ASN1_DISPLAYTEXT | \
384 B_ASN1_NUMERICSTRING | B_ASN1_T61STRING | B_ASN1_UNIVERSALSTRING)
385
parse_ia5(QString * single,QString * adv) const386 bool x509v3ext::parse_ia5(QString *single, QString *adv) const
387 {
388 ASN1_STRING *str = (ASN1_STRING *)d2i();
389 QString ret;
390
391 if (!str) {
392 const unsigned char *p = getData()->data;
393 str = d2i_ASN1_OCTET_STRING(NULL, &p, getData()->length);
394 if (ign_openssl_error() || !str)
395 return false;
396 ret = QString("<ERROR: NOT IA5 but %1>%2").
397 arg(asn1Type2Name(str->type)).
398 arg(QString(asn1ToQString(str)));
399 } else {
400 ret = QString(asn1ToQString(str));
401 }
402 if (single)
403 *single = ret;
404 else if (adv)
405 *adv = QString("%1=%2\n").arg(OBJ_nid2sn(nid())).arg(ret) +*adv;
406
407 ASN1_STRING_free(str);
408 return true;
409 }
410
parse_generalName(QString * single,QString * adv) const411 bool x509v3ext::parse_generalName(QString *single, QString *adv) const
412 {
413 bool retval = true;
414 QString sect, ret;
415 STACK_OF(GENERAL_NAME) *gens = (STACK_OF(GENERAL_NAME) *)d2i();
416
417 if (!gens)
418 return false;
419
420 QString tag = OBJ_nid2sn(nid());
421
422 if (!genNameStack2conf(gens, tag, &ret, §))
423 retval = false;
424 else if (sect.isEmpty() && single) {
425 *single = parse_critical() + ret;
426 } else if (adv) {
427 *adv = QString("%1=%2\n").arg(tag).
428 arg(parse_critical() +ret) + *adv + sect;
429 }
430 sk_GENERAL_NAME_free(gens);
431 return retval;
432 }
433
parse_eku(QString * single,QString * adv) const434 bool x509v3ext::parse_eku(QString *single, QString *adv) const
435 {
436 EXTENDED_KEY_USAGE *eku = (EXTENDED_KEY_USAGE *)d2i();
437 QStringList sl;
438 int i;
439
440 if (!eku)
441 return false;
442
443 for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
444 sl << QString(OBJ_obj2sn(sk_ASN1_OBJECT_value(eku, i)));
445 }
446 QString r = parse_critical() + sl.join(", ");
447 if (single)
448 *single = r;
449 else if (adv)
450 *adv = QString("%1=%2\n").arg(OBJ_nid2sn(nid())).arg(r) + *adv;
451
452 EXTENDED_KEY_USAGE_free(eku);
453 return true;
454 }
455
parse_ainfo(QString * single,QString * adv) const456 bool x509v3ext::parse_ainfo(QString *single, QString *adv) const
457 {
458 bool retval = true;
459 QString sect, ret;
460 QString tag = OBJ_nid2sn(nid());
461 QStringList sl;
462 int i;
463
464 AUTHORITY_INFO_ACCESS *ainfo = (AUTHORITY_INFO_ACCESS *)d2i();
465
466 if (!ainfo)
467 return false;
468
469 for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ainfo); i++) {
470 QString one;
471 ACCESS_DESCRIPTION *desc = sk_ACCESS_DESCRIPTION_value(ainfo, i);
472 if (!genName2conf(desc->location,
473 QString("%1_%2").arg(tag).arg(i), &one, §))
474 {
475 retval = false;
476 break;
477 }
478 sl << QString("%1;%2").arg(OBJ_obj2sn(desc->method)).arg(one);
479 }
480 if (retval) {
481 ret = vlist2Section(sl, tag, §);
482 if (sect.isEmpty() && sk_ACCESS_DESCRIPTION_num(ainfo) == 1 && single) {
483 *single = parse_critical() + ret;
484 } else if (adv) {
485 *adv = QString("%1=%2\n").arg(tag).
486 arg(parse_critical() + ret) + *adv + sect;
487 }
488 }
489 AUTHORITY_INFO_ACCESS_free(ainfo);
490 return retval;
491 }
492
493 static const BIT_STRING_BITNAME reason_flags[] = {
494 {0, "", "unused"},
495 {1, "", "keyCompromise"},
496 {2, "", "CACompromise"},
497 {3, "", "affiliationChanged"},
498 {4, "", "superseded"},
499 {5, "", "cessationOfOperation"},
500 {6, "", "certificateHold"},
501 {7, "", "privilegeWithdrawn"},
502 {8, "", "AACompromise"},
503 {-1, NULL, NULL}
504 };
505
parse_bits(const BIT_STRING_BITNAME * flags,ASN1_BIT_STRING * str)506 static QString parse_bits(const BIT_STRING_BITNAME *flags,
507 ASN1_BIT_STRING *str)
508 {
509 const BIT_STRING_BITNAME *pbn;
510 QStringList r;
511 for (pbn = flags; pbn->sname; pbn++) {
512 if (ASN1_BIT_STRING_get_bit(str, pbn->bitnum))
513 r << QString(pbn->sname);
514 }
515 return r.join(", ");
516 }
517
parse_Crldp(QString * single,QString * adv) const518 bool x509v3ext::parse_Crldp(QString *single, QString *adv) const
519 {
520 QString othersect;
521 QStringList crldps;
522 const char *sn = OBJ_nid2sn(nid());
523
524 STACK_OF(DIST_POINT) *crld = (STACK_OF(DIST_POINT)*)d2i();
525
526 if (!crld)
527 return false;
528
529 if (sk_DIST_POINT_num(crld) == 1 && single) {
530 DIST_POINT *point = sk_DIST_POINT_value(crld, 0);
531 if (point->distpoint && !point->reasons && !point->CRLissuer &&
532 !point->distpoint->type)
533 {
534 QString sect, ret;
535 if (!genNameStack2conf(point->distpoint->name.fullname,
536 "", &ret, §))
537 goto could_not_parse;
538
539 if (sect.isEmpty()) {
540 if (single)
541 *single = parse_critical() +ret;
542 else if (adv)
543 *adv = QString("%1=%2\n").arg(sn).
544 arg(parse_critical() +ret) +*adv;
545 return true;
546 }
547 }
548 }
549 for(int i = 0; i < sk_DIST_POINT_num(crld); i++) {
550 DIST_POINT *point = sk_DIST_POINT_value(crld, i);
551 QString tag = QString("crlDistributionPoint%1_sect").arg(i);
552 QString crldpsect = QString("\n[%1]\n").arg(tag);
553 if (point->distpoint) {
554 if (!point->distpoint->type) {
555 QString ret;
556 if (!genNameStack2conf(point->distpoint->name.fullname,
557 tag + "_fullname", &ret, &othersect))
558 goto could_not_parse;
559
560 crldpsect += "fullname=" + ret +"\n";
561 } else {
562 QString mysect = tag + "_relativename";
563 x509name xn(point->distpoint->name.relativename);
564 crldpsect += "relativename=" + mysect + "\n";
565 othersect += QString("\n[%1]\n").arg(mysect) +
566 xn.taggedValues();
567 }
568 }
569 if (point->reasons) {
570 crldpsect += QString("reasons=%1\n").
571 arg(parse_bits(reason_flags, point->reasons));
572 }
573 if (point->CRLissuer) {
574 QString ret;
575 if (genNameStack2conf(point->CRLissuer,
576 tag +"_crlissuer", &ret, &othersect))
577 goto could_not_parse;
578 crldpsect += "CRLissuer=" + ret + "\n";
579 }
580 crldps << tag;
581 othersect = crldpsect + othersect;
582 }
583 sk_DIST_POINT_free(crld);
584 if (crldps.size() == 0)
585 return true;
586 if (adv) {
587 *adv = QString("%1=%2\n").arg(sn).
588 arg(parse_critical() + crldps.join(", ")) +
589 *adv + othersect;
590
591 #if OPENSSL_VERSION_NUMBER < 0x10000000L
592 *adv = QString( "\n"
593 "# This syntax only works for openssl >= 1.0.0\n"
594 "# But this is %1\n"
595 "# ").arg(OPENSSL_VERSION_TEXT) + *adv;
596 #endif
597 }
598 return true;
599
600 could_not_parse:
601 sk_DIST_POINT_free(crld);
602 return false;
603 }
604
gen_cpol_notice(QString tag,USERNOTICE * notice,QString * adv)605 static void gen_cpol_notice(QString tag, USERNOTICE *notice, QString *adv)
606 {
607 *adv += QString("\n[%1]\n").arg(tag);
608 if (notice->exptext) {
609 *adv += QString("explicitText=%1\n").
610 arg(asn1ToQString(notice->exptext, true));
611 }
612 if (notice->noticeref) {
613 NOTICEREF *ref = notice->noticeref;
614 QStringList sl;
615 int i;
616 *adv += QString("organization=%1\n").
617 arg(asn1ToQString(ref->organization, true));
618 for (i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) {
619 a1int num(sk_ASN1_INTEGER_value(ref->noticenos, i));
620 sl << num.toDec();
621 }
622 if (sl.size())
623 *adv += QString("noticeNumbers=%1\n").
624 arg(sl.join(", "));
625 }
626 }
627
gen_cpol_qual_sect(QString tag,POLICYINFO * pinfo,QString * adv)628 static bool gen_cpol_qual_sect(QString tag, POLICYINFO *pinfo, QString *adv)
629 {
630 QString polsect = QString("\n[%1]\n").arg(tag);
631 QString noticetag, _adv;
632 STACK_OF(POLICYQUALINFO) *quals = pinfo->qualifiers;
633 int i;
634
635 if (!quals)
636 return false;
637
638 if (!adv)
639 adv = &_adv;
640
641 polsect += QString("policyIdentifier=%1\n").
642 arg(obj2SnOid(pinfo->policyid));
643
644 for (i = 0; i < sk_POLICYQUALINFO_num(quals); i++) {
645 POLICYQUALINFO *qualinfo = sk_POLICYQUALINFO_value(quals, i);
646 switch (OBJ_obj2nid(qualinfo->pqualid)) {
647 case NID_id_qt_cps:
648 polsect += QString("CPS.%1=%2\n").arg(i).
649 arg(asn1ToQString(qualinfo->d.cpsuri, true));
650 break;
651 case NID_id_qt_unotice:
652 noticetag = QString("%1_notice%2_sect").arg(tag).arg(i);
653 polsect += QString("userNotice.%1=@%2\n").arg(i).
654 arg(noticetag);
655 gen_cpol_notice(noticetag, qualinfo->d.usernotice, adv);
656 break;
657 default:
658 return false;
659 }
660 }
661 *adv = polsect + *adv;
662 return true;
663 }
664
665
parse_certpol(QString *,QString * adv) const666 bool x509v3ext::parse_certpol(QString *, QString *adv) const
667 {
668 bool retval = true;
669 QStringList pols;
670 QString myadv;
671 int i;
672 STACK_OF(POLICYINFO) *pol = (STACK_OF(POLICYINFO) *)d2i();
673
674 if (!pol)
675 return false;
676
677 for (i = 0; i < sk_POLICYINFO_num(pol); i++) {
678 POLICYINFO *pinfo = sk_POLICYINFO_value(pol, i);
679 if (!pinfo->qualifiers) {
680 pols << obj2SnOid(pinfo->policyid);
681 continue;
682 }
683 QString tag = QString("certpol%1_sect").arg(i);
684 pols << QString("@") + tag;
685 if (!gen_cpol_qual_sect(tag, pinfo, &myadv)) {
686 retval = false;
687 break;
688 }
689 }
690 if (retval && adv)
691 *adv = QString("certificatePolicies=%1ia5org,%2\n").
692 arg(parse_critical()).arg(pols.join(", ")) + *adv + myadv;
693 sk_POLICYINFO_free(pol);
694 return retval;
695 }
696
parse_bc(QString * single,QString * adv) const697 bool x509v3ext::parse_bc(QString *single, QString *adv) const
698 {
699 BASIC_CONSTRAINTS *bc = (BASIC_CONSTRAINTS *)d2i();
700
701 if (!bc)
702 return false;
703
704 QString ret = a1int(bc->pathlen).toDec();
705 if (!ret.isEmpty())
706 ret = ",pathlen:" + ret;
707 ret = parse_critical() + (bc->ca ? "CA:TRUE" : "CA:FALSE") + ret;
708 if (single)
709 *single = ret;
710 else if (adv)
711 *adv = QString("%1=%2\n").arg(OBJ_nid2sn(nid())).arg(ret) +*adv;
712 BASIC_CONSTRAINTS_free(bc);
713 return true;
714 }
715
716 static const BIT_STRING_BITNAME key_usage_type_table[] = {
717 {0, "Digital Signature", "digitalSignature"},
718 {1, "Non Repudiation", "nonRepudiation"},
719 {2, "Key Encipherment", "keyEncipherment"},
720 {3, "Data Encipherment", "dataEncipherment"},
721 {4, "Key Agreement", "keyAgreement"},
722 {5, "Certificate Sign", "keyCertSign"},
723 {6, "CRL Sign", "cRLSign"},
724 {7, "Encipher Only", "encipherOnly"},
725 {8, "Decipher Only", "decipherOnly"},
726 {-1, NULL, NULL}
727 };
728
729 static const BIT_STRING_BITNAME ns_cert_type_table[] = {
730 {0, "SSL Client", "client"},
731 {1, "SSL Server", "server"},
732 {2, "S/MIME", "email"},
733 {3, "Object Signing", "objsign"},
734 {4, "Unused", "reserved"},
735 {5, "SSL CA", "sslCA"},
736 {6, "S/MIME CA", "emailCA"},
737 {7, "Object Signing CA", "objCA"},
738 {-1, NULL, NULL}
739 };
740
parse_bitstring(QString * single,QString * adv) const741 bool x509v3ext::parse_bitstring(QString *single, QString *adv) const
742 {
743 ASN1_BIT_STRING *bs;
744 const BIT_STRING_BITNAME *bnames;
745 int n = nid();
746
747 switch (n) {
748 case NID_key_usage: bnames = key_usage_type_table; break;
749 case NID_netscape_cert_type: bnames = ns_cert_type_table; break;
750 default: return false;
751 }
752 bs = (ASN1_BIT_STRING *)d2i();
753
754 if (!bs)
755 return false;
756
757 QString ret = parse_critical() + parse_bits(bnames, bs);
758 if (single)
759 *single = ret;
760 else if (adv)
761 *adv = QString("%1=%2\n").arg(OBJ_nid2sn(nid())).arg(ret) +*adv;
762 ASN1_BIT_STRING_free(bs);
763 return true;
764 }
765
parse_sKeyId(QString *,QString * adv) const766 bool x509v3ext::parse_sKeyId(QString *, QString *adv) const
767 {
768 if (adv)
769 *adv = QString("%1=hash\n").arg(OBJ_nid2sn(nid())) + *adv;
770 return true;
771 }
772
parse_aKeyId(QString *,QString * adv) const773 bool x509v3ext::parse_aKeyId(QString *, QString *adv) const
774 {
775 QStringList ret;
776 AUTHORITY_KEYID *akeyid = (AUTHORITY_KEYID *)d2i();
777
778 if (!akeyid)
779 return false;
780
781 if (akeyid->keyid)
782 ret << "keyid";
783 if (akeyid->issuer)
784 ret << "issuer:always";
785 if (adv)
786 *adv = QString("%1=%2\n").arg(OBJ_nid2sn(nid())).
787 arg(ret.join(", ")) + *adv;
788 AUTHORITY_KEYID_free(akeyid);
789 return true;
790 }
791
parse_generic(QString *,QString * adv) const792 bool x509v3ext::parse_generic(QString *, QString *adv) const
793 {
794 const ASN1_OBJECT *o = object();
795 QString der, obj = o ? obj2SnOid(o) : QString("<ERROR>");
796 ASN1_OCTET_STRING *v = getData();
797
798 for (int i=0; i<v->length; i++)
799 der += QString(":%1").arg((int)(v->data[i]), 2, 16, QChar('0'));
800
801 if (adv)
802 *adv = QString("%1=%2DER%3\n").arg(obj).
803 arg(parse_critical()).arg(der) +
804 *adv;
805 return true;
806 }
807
parse_inhibitAnyPolicy(QString *,QString * adv) const808 bool x509v3ext::parse_inhibitAnyPolicy(QString *, QString *adv) const
809 {
810 ASN1_INTEGER *a = (ASN1_INTEGER *)d2i();
811
812 if (!a)
813 return false;
814
815 a1int val(a);
816 if (adv) {
817 *adv = QString("%1=%2%3\n").arg(OBJ_nid2sn(nid())).
818 arg(parse_critical()).arg(val.toDec()) + *adv;
819 }
820 ASN1_INTEGER_free(a);
821 return true;
822 }
823
parse_policyConstraints(QString *,QString * adv) const824 bool x509v3ext::parse_policyConstraints(QString *, QString *adv) const
825 {
826 QStringList v;
827 a1int a1null(0L), a;
828 POLICY_CONSTRAINTS *pol = (POLICY_CONSTRAINTS *)d2i();
829
830 if (!pol)
831 return false;
832
833 a = a1int(pol->requireExplicitPolicy);
834 if (a != a1null)
835 v << QString("requireExplicitPolicy:%1").arg(a.toDec());
836
837 a = a1int(pol->inhibitPolicyMapping);
838 if (a != a1null)
839 v << QString("inhibitPolicyMapping:%1").arg(a.toDec());
840
841 if (adv)
842 *adv = QString("%1=%2%3\n").arg(OBJ_nid2sn(nid())).
843 arg(parse_critical()).arg(v.join(", ")) + *adv;
844 POLICY_CONSTRAINTS_free(pol);
845 return true;
846
847 }
848
parse_policyMappings(QString *,QString * adv) const849 bool x509v3ext::parse_policyMappings(QString *, QString *adv) const
850 {
851 bool retval = true;
852 QStringList polMaps;
853 QString myadv;
854 POLICY_MAPPINGS *pmaps = (POLICY_MAPPINGS *)d2i();
855
856 if (!pmaps)
857 return false;
858
859 for (int i = 0; i < sk_POLICY_MAPPING_num(pmaps); i++) {
860 POLICY_MAPPING *pmap = sk_POLICY_MAPPING_value(pmaps, i);
861 polMaps << QString("%1 = %2").
862 arg(obj2SnOid(pmap->issuerDomainPolicy)).
863 arg(obj2SnOid(pmap->subjectDomainPolicy));
864 }
865 if (polMaps.size() > 0 && adv) {
866 *adv = QString("policyMappings=%1@policyMappings_sect\n").
867 arg(parse_critical()) + *adv +
868 QString("[policyMappings_sect]\n") + polMaps.join("\n");
869 }
870 sk_POLICY_MAPPING_free(pmaps);
871 return retval;
872 }
873
nameConstraint(STACK_OF (GENERAL_SUBTREE)* trees,QString prefix,QString tag,QString * single,QString * sect)874 static bool nameConstraint(STACK_OF(GENERAL_SUBTREE) *trees,
875 QString prefix, QString tag, QString *single, QString *sect)
876 {
877 QStringList sl;
878 for (int i = 0; i < sk_GENERAL_SUBTREE_num(trees); i++) {
879 QString one;
880 GENERAL_SUBTREE *tree = sk_GENERAL_SUBTREE_value(trees, i);
881 if (!genName2conf(tree->base,
882 QString("%1_%2").arg(tag).arg(i), &one, sect))
883 {
884 return false;
885 }
886 qDebug("%s: %d '%s'\n", __func__, i, CCHAR(one));
887 sl << prefix + ";" + one;
888 }
889 *single = vlist2Section(sl, tag+prefix, sect);
890 qDebug("Single: '%s'\n", CCHAR(*single));
891 return true;
892 }
893
parse_nameConstraints(QString *,QString * adv) const894 bool x509v3ext::parse_nameConstraints(QString *, QString *adv) const
895 {
896 bool retval = true;
897 QString sect, ret;
898 QStringList permEx;
899 QString tag = OBJ_nid2sn(nid());
900 NAME_CONSTRAINTS *cons = (NAME_CONSTRAINTS *)d2i();
901
902 if (!cons)
903 return false;
904
905 if (!nameConstraint(cons->permittedSubtrees, "permitted",
906 tag, &ret, §))
907 retval = false;
908 if (ret.size() > 0)
909 permEx << ret;
910 if (!nameConstraint(cons->excludedSubtrees, "excluded",
911 tag, &ret, §))
912 retval = false;
913 if (ret.size() > 0)
914 permEx << ret;
915
916 if (adv && retval &&permEx.size() > 0) {
917 ret = permEx.join(", ");
918 qDebug("%s %d '%s'\n", __func__, retval, CCHAR(ret));
919 *adv = QString("%1=%2\n").arg(tag).
920 arg(parse_critical() +ret) + *adv + sect;
921 }
922 NAME_CONSTRAINTS_free(cons);
923 return retval;
924 }
925
genConf(QString * single,QString * adv) const926 bool x509v3ext::genConf(QString *single, QString *adv) const
927 {
928 int n = nid();
929 switch (n) {
930 case NID_crl_distribution_points:
931 return parse_Crldp(single, adv);
932 case NID_subject_alt_name:
933 case NID_issuer_alt_name:
934 return parse_generalName(single, adv);
935 case NID_info_access:
936 return parse_ainfo(single, adv);
937 case NID_ext_key_usage:
938 return parse_eku(single, adv);
939 case NID_certificate_policies:
940 return parse_certpol(single, adv);
941 case NID_netscape_comment:
942 case NID_netscape_base_url:
943 case NID_netscape_revocation_url:
944 case NID_netscape_ca_revocation_url:
945 case NID_netscape_renewal_url:
946 case NID_netscape_ca_policy_url:
947 case NID_netscape_ssl_server_name:
948 return parse_ia5(single, adv);
949 case NID_basic_constraints:
950 return parse_bc(single, adv);
951 case NID_key_usage:
952 case NID_netscape_cert_type:
953 return parse_bitstring(single, adv);
954 case NID_subject_key_identifier:
955 return parse_sKeyId(single, adv);
956 case NID_authority_key_identifier:
957 return parse_aKeyId(single, adv);
958 case NID_inhibit_any_policy:
959 return parse_inhibitAnyPolicy(single, adv);
960 case NID_policy_constraints:
961 return parse_policyConstraints(single, adv);
962 case NID_policy_mappings:
963 return parse_policyMappings(single, adv);
964 case NID_name_constraints:
965 return parse_nameConstraints(single, adv);
966 case NID_id_pkix_OCSP_noCheck:
967 if (adv)
968 *adv = "noCheck = ignored\n" + *adv;
969 return true;
970 default:
971 return parse_generic(single, adv);
972 }
973 return false;
974 }
975
getHtml() const976 QString x509v3ext::getHtml() const
977 {
978 QString html;
979 html = "<b><u>" + getObject();
980 if (getCritical() != 0)
981 html += " <font color=\"red\">critical</font>";
982 html += ":</u></b><br><tt>" + getHtmlValue() + "</tt>";
983 return html;
984 }
985
getConsole(const QString & indent) const986 QString x509v3ext::getConsole(const QString &indent) const
987 {
988 QString text, twoind = indent + indent;
989 text = indent + COL_BOLD COL_UNDER + getObject();
990 if (getCritical() != 0)
991 text += " " COL_RED COL_UNDER "[critical]";
992 text += COL_RESET "\n" + twoind + getConsoleValue(twoind);
993 return text;
994 }
995
get() const996 X509_EXTENSION *x509v3ext::get() const
997 {
998 return X509_EXTENSION_dup(ext);
999 }
1000
isValid() const1001 bool x509v3ext::isValid() const
1002 {
1003 return ext && getData() && getData()->length > 0 &&
1004 OBJ_obj2nid(X509_EXTENSION_get_object(ext)) != NID_undef;
1005 }
1006
1007 /*************************************************************/
1008
genConf(int nid,QString * single,QString * adv)1009 bool extList::genConf(int nid, QString *single, QString *adv)
1010 {
1011 int i = idxByNid(nid);
1012 if (i != -1) {
1013 if (at(i).genConf(single, adv))
1014 removeAt(i);
1015 ign_openssl_error();
1016 return true;
1017 }
1018 return false;
1019 }
1020
genGenericConf(QString * adv)1021 void extList::genGenericConf(QString *adv)
1022 {
1023 for (int i=0; i< size();) {
1024 if (at(i).genConf(NULL, adv) || at(i).parse_generic(NULL, adv))
1025 removeAt(i);
1026 else
1027 i++;
1028 ign_openssl_error();
1029 }
1030 }
1031
setStack(const STACK_OF (X509_EXTENSION)* st,int start)1032 void extList::setStack(const STACK_OF(X509_EXTENSION) *st, int start)
1033 {
1034 clear();
1035 int cnt = sk_X509_EXTENSION_num(st);
1036 x509v3ext e;
1037 for (int i=start; i<cnt; i++) {
1038 e.set(sk_X509_EXTENSION_value(st,i));
1039 append(e);
1040 }
1041 }
1042
STACK_OF(X509_EXTENSION)1043 STACK_OF(X509_EXTENSION) *extList::getStack()
1044 {
1045 STACK_OF(X509_EXTENSION) *sk = sk_X509_EXTENSION_new_null();
1046 foreach(const x509v3ext &e, *this)
1047 sk_X509_EXTENSION_push(sk, e.get());
1048 return sk;
1049 }
1050
search(const QRegExp & pattern)1051 bool extList::search(const QRegExp &pattern)
1052 {
1053 foreach(const x509v3ext &e, *this)
1054 if (e.getValue().contains(pattern))
1055 return true;
1056 return false;
1057 }
getHtml(const QString & sep)1058 QString extList::getHtml(const QString &sep)
1059 {
1060 x509v3ext e;
1061 QStringList s;
1062 foreach(const x509v3ext &e, *this)
1063 s << e.getHtml();
1064 QString a = s.join(sep);
1065 return a;
1066 }
1067
getConsole(const QString & indent) const1068 QString extList::getConsole(const QString &indent) const
1069 {
1070 x509v3ext e;
1071 QStringList s;
1072 foreach(const x509v3ext &e, *this)
1073 s << e.getConsole(indent);
1074 QString a = "\n" + s.join("\n");
1075 return a;
1076 }
1077
1078
delByNid(int nid)1079 bool extList::delByNid(int nid)
1080 {
1081 for(int i = 0; i< size(); i++) {
1082 if (at(i).nid() == nid) {
1083 removeAt(i);
1084 return true;
1085 }
1086 }
1087 return false;
1088 }
1089
idxByNid(int nid)1090 int extList::idxByNid(int nid)
1091 {
1092 for(int i = 0; i< size(); i++) {
1093 if (at(i).nid() == nid) {
1094 return i;
1095 }
1096 }
1097 return -1;
1098 }
1099
delInvalid(void)1100 int extList::delInvalid(void)
1101 {
1102 int removed=0;
1103 for(int i = 0; i<size(); i++) {
1104 if (!at(i).isValid()) {
1105 removeAt(i);
1106 removed=1;
1107 i--;
1108 }
1109 }
1110 return removed;
1111 }
1112