1 /* vi: set sw=4 ts=4:
2 *
3 * Copyright (C) 2001 - 2020 Christian Hohnstaedt.
4 *
5 * All rights reserved.
6 */
7
8
9 #include "pki_x509.h"
10 #include "pki_x509req.h"
11 #include "pki_evp.h"
12 #include "pki_scard.h"
13 #include "pki_crl.h"
14 #include "db_base.h"
15 #include "func.h"
16 #include "base.h"
17 #include "exception.h"
18 #include "pass_info.h"
19 #include "openssl_compat.h"
20 #include "widgets/XcaWarning.h"
21
pki_x509(X509 * c)22 pki_x509::pki_x509(X509 *c)
23 :pki_x509super()
24 {
25 init();
26 cert = c;
27 pki_openssl_error();
28 }
29
pki_x509(const pki_x509 * crt)30 pki_x509::pki_x509(const pki_x509 *crt)
31 :pki_x509super(crt)
32 {
33 init();
34 cert = X509_dup(crt->cert);
35 pki_openssl_error();
36 issuerSqlId = crt->issuerSqlId;
37 setRefKey(crt->getRefKey());
38 caTemplateSqlId = crt->caTemplateSqlId;
39 revocation = crt->revocation;
40 crlDays = crt->crlDays;
41 crlExpire = crt->crlExpire;
42 pki_openssl_error();
43 }
44
pki_x509(const QString & name)45 pki_x509::pki_x509(const QString &name)
46 :pki_x509super(name)
47 {
48 init();
49 cert = X509_new();
50 X509_set_version(cert, 2);
51 pki_openssl_error();
52 }
53
getMsg(msg_type msg) const54 QString pki_x509::getMsg(msg_type msg) const
55 {
56 /*
57 * We do not construct english sentences from fragments
58 * to allow proper translations.
59 * The drawback are all the slightly different duplicated messages
60 *
61 * %1 will be replaced by the internal name of the certificate
62 */
63 switch (msg) {
64 case msg_import: return tr("Successfully imported the certificate '%1'");
65 case msg_delete: return tr("Delete the certificate '%1'?");
66 case msg_create: return tr("Successfully created the certificate '%1'");
67 /* %1: Number of certs; %2: list of cert names */
68 case msg_delete_multi: return tr("Delete the %1 certificates: %2?");
69 }
70 return pki_base::getMsg(msg);
71 }
72
resetX509ReqCount() const73 void pki_x509::resetX509ReqCount() const
74 {
75 QList<pki_x509req *> reqs = Store.sqlSELECTpki<pki_x509req>(
76 "SELECT item FROM x509super LEFT JOIN items ON items.id = x509super.item "
77 "WHERE key_hash=? AND items.type=?",
78 QList<QVariant>() << QVariant(pubHash()) << QVariant(x509_req));
79
80 foreach(pki_x509req *req, reqs)
81 req->resetX509count();
82 }
83
insertSqlData()84 QSqlError pki_x509::insertSqlData()
85 {
86 XSqlQuery q;
87 a1time now;
88 pki_x509 *signer = findIssuer();
89 QSqlError e = pki_x509super::insertSqlData();
90 if (e.isValid())
91 return e;
92
93 SQL_PREPARE(q, "INSERT INTO certs (item, hash, iss_hash, serial, issuer, "
94 "ca, cert) "
95 "VALUES (?, ?, ?, ?, ?, ?, ?)");
96 q.bindValue(0, sqlItemId);
97 q.bindValue(1, hash());
98 q.bindValue(2, getIssuerName().hashNum());
99 q.bindValue(3, getSerial().toHex());
100 q.bindValue(4, signer ? signer->getSqlItemId() : QVariant());
101 q.bindValue(5, (int)isCA());
102 q.bindValue(6, i2d_b64());
103 q.exec();
104
105 resetX509ReqCount();
106
107 if (!isCA())
108 return q.lastError();
109
110 SQL_PREPARE(q, "INSERT INTO authority (item, template, crlExpire, crlNo, crlDays) "
111 "VALUES (?, ?, ?, 0, ?)");
112 q.bindValue(0, sqlItemId);
113 q.bindValue(1, caTemplateSqlId);
114 q.bindValue(2, crlExpire.toPlain());
115 q.bindValue(3, crlDays);
116 q.exec();
117 if (fromDataRevList.size() > 0)
118 fromDataRevList.sqlUpdate(sqlItemId);
119 return q.lastError();
120 }
121
restoreSql(const QSqlRecord & rec)122 void pki_x509::restoreSql(const QSqlRecord &rec)
123 {
124 pki_x509super::restoreSql(rec);
125 QByteArray ba = QByteArray::fromBase64(
126 rec.value(VIEW_x509_cert).toByteArray());
127 d2i(ba);
128 issuerSqlId = rec.value(VIEW_x509_issuer);
129 crlNumber.set(rec.value(VIEW_x509_auth_crlNo).toUInt());
130 crlExpire.fromPlain(rec.value(VIEW_x509_auth_crlExpire).toString());
131 caTemplateSqlId = rec.value(VIEW_x509_auth_template);
132 if (!rec.isNull(VIEW_x509_auth_crlDays))
133 crlDays = rec.value(VIEW_x509_auth_crlDays).toInt();
134 else
135 crlDays = 30;
136 if (!rec.isNull(VIEW_x509_revocation))
137 revocation = x509rev(rec, VIEW_x509_revocation);
138 }
139
deleteSqlData()140 QSqlError pki_x509::deleteSqlData()
141 {
142 XSqlQuery q;
143 QSqlError e = pki_x509super::deleteSqlData();
144 QStringList tasks; tasks
145 << "DELETE FROM certs WHERE item=?"
146 << "DELETE FROM authority WHERE item=?"
147 << "UPDATE crls SET issuer=NULL WHERE issuer=?"
148 << "UPDATE certs SET issuer=NULL WHERE issuer=?"
149 << "DELETE FROM revocations WHERE caId=?"
150 ;
151 foreach(QString task, tasks) {
152 SQL_PREPARE(q, task);
153 q.bindValue(0, sqlItemId);
154 q.exec();
155 e = q.lastError();
156 if (e.isValid())
157 return e;
158 }
159 // Select affected items
160 q = Store.sqlSELECTpki(
161 "SELECT DISTINCT items.id FROM items, certs, crls "
162 "WHERE (items.id = certs.item OR items.id = crls.item) "
163 "AND crls.issuer = ? AND certs.issuer = ?",
164 QList<QVariant>() << QVariant(sqlItemId)
165 << QVariant(sqlItemId));
166
167 while (q.next())
168 AffectedItems(q.value(0));
169
170 resetX509ReqCount();
171 return q.lastError();
172 }
173
findIssuer()174 pki_x509 *pki_x509::findIssuer()
175 {
176 XSqlQuery q;
177 pki_x509 *issuer;
178 unsigned hash;
179
180 if ((issuer = getSigner()) != NULL)
181 return issuer;
182 // first check for self-signed
183 if (verify(this))
184 return this;
185
186 hash = getIssuerName().hashNum();
187 /* Select X509 CA certificates with subject-hash == hash */
188 SQL_PREPARE(q, "SELECT x509super.item from x509super "
189 "JOIN certs ON certs.item = x509super.item "
190 "WHERE certs.ca=1 AND x509super.subj_hash=?");
191 q.bindValue(0, hash);
192 q.exec();
193 while (q.next()) {
194 issuer = Store.lookupPki<pki_x509>(q.value(0));
195 if (!issuer) {
196 qDebug("Certificate with id %d not found",
197 q.value(0).toInt());
198 }
199 if (verify(issuer)) {
200 return issuer;
201 }
202 }
203 return NULL;
204 }
205
fromPEM_BIO(BIO * bio,const QString & fname)206 void pki_x509::fromPEM_BIO(BIO *bio, const QString &fname)
207 {
208 X509 *_cert;
209 _cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
210 openssl_error(fname);
211 X509_free(cert);
212 cert = _cert;
213 }
214
fload(const QString & fname)215 void pki_x509::fload(const QString &fname)
216 {
217 X509 *_cert;
218 XFile file(fname);
219 file.open_read();
220 _cert = PEM_read_X509(file.fp(), NULL, NULL, NULL);
221 if (!_cert) {
222 pki_ign_openssl_error();
223 file.retry_read();
224 _cert = d2i_X509_fp(file.fp(), NULL);
225 }
226 if (pki_ign_openssl_error() || !_cert) {
227 if (_cert)
228 X509_free(_cert);
229 throw errorEx(tr("Unable to load the certificate in file %1. Tried PEM and DER certificate.").arg(fname));
230 }
231 X509_free(cert);
232 cert = _cert;
233 }
234
~pki_x509()235 pki_x509::~pki_x509()
236 {
237 if (cert) {
238 X509_free(cert);
239 }
240 pki_openssl_error();
241 }
242
init()243 void pki_x509::init()
244 {
245 caTemplateSqlId = QVariant();
246 crlDays = 30;
247 crlExpire.setUndefined();
248 cert = NULL;
249 pkiType = x509;
250 }
251
setSerial(const a1int & serial)252 void pki_x509::setSerial(const a1int &serial)
253 {
254 X509_set_serialNumber(cert, serial.get());
255 pki_openssl_error();
256 }
257
getSerial() const258 a1int pki_x509::getSerial() const
259 {
260 a1int a(X509_get_serialNumber(cert));
261 pki_openssl_error();
262 return a;
263 }
264
getBySerial(const a1int & a) const265 pki_x509 *pki_x509::getBySerial(const a1int &a) const
266 {
267 foreach(pki_base *p, childItems) {
268 pki_x509 *pki = static_cast<pki_x509 *>(p);
269 if (a == pki->getSerial())
270 return pki;
271 }
272 return NULL;
273 }
274
hashInfo(const EVP_MD * md) const275 a1int pki_x509::hashInfo(const EVP_MD *md) const
276 {
277 unsigned char digest[EVP_MAX_MD_SIZE];
278 unsigned len = 0;
279
280 if (!X509_digest(cert, md, digest, &len))
281 pki_openssl_error();
282 a1int a;
283 a.setRaw(digest,len);
284 return a;
285 }
286
load_token(pkcs11 & p11,CK_OBJECT_HANDLE object)287 void pki_x509::load_token(pkcs11 &p11, CK_OBJECT_HANDLE object)
288 {
289 QString desc;
290
291 pk11_attr_ulong type(CKA_CERTIFICATE_TYPE);
292 p11.loadAttribute(type, object);
293 if (type.getValue() != CKC_X_509)
294 throw errorEx(QString("Unsupported Certificate type %1"
295 ).arg(type.getValue()));
296
297 try {
298 pk11_attr_data label(CKA_LABEL);
299 p11.loadAttribute(label, object);
300 desc = label.getText();
301 } catch(errorEx &err) {
302 qDebug("No Cert Label: %s", err.getCString());
303 // IGNORE
304 }
305 pk11_attr_data x509(CKA_VALUE);
306 p11.loadAttribute(x509, object);
307 QByteArray der = x509.getData();
308 d2i(der);
309
310 if (desc.isEmpty()) {
311 try {
312 x509name xn;
313
314 pk11_attr_data subj(CKA_SUBJECT);
315 p11.loadAttribute(subj, object);
316 QByteArray der = subj.getData();
317 xn.d2i(der);
318 desc = xn.getMostPopular();
319 pki_openssl_error();
320 } catch(errorEx &err) {
321 qDebug("No Cert Subject: %s", err.getCString());
322 // IGNORE
323 }
324 }
325 setIntName(desc);
326 pkiSource = token;
327 pki_openssl_error();
328 }
329
d2i(QByteArray & ba)330 void pki_x509::d2i(QByteArray &ba)
331 {
332 X509 *c = (X509*)d2i_bytearray(D2I_VOID(d2i_X509), ba);
333 if (c) {
334 X509_free(cert);
335 cert = c;
336 }
337 pki_openssl_error();
338 }
339
i2d() const340 QByteArray pki_x509::i2d() const
341 {
342 return i2d_bytearray(I2D_VOID(i2d_X509), cert);
343 }
344
store_token(bool alwaysSelect)345 void pki_x509::store_token(bool alwaysSelect)
346 {
347 pki_scard *card = NULL;
348 slotid slot;
349 x509name xname;
350 QList<CK_OBJECT_HANDLE> objects;
351
352 pkcs11 p11;
353
354 pki_key *privkey = getRefKey();
355 if (!privkey || !privkey->isToken() || alwaysSelect) {
356 if (!p11.selectToken(&slot, NULL))
357 return;
358 } else {
359 card = dynamic_cast<pki_scard *>(privkey);
360 if (!card || !card->prepare_card(&slot))
361 return;
362 }
363
364 pk11_attlist p11_atts;
365 p11_atts <<
366 pk11_attr_ulong(CKA_CLASS, CKO_CERTIFICATE) <<
367 pk11_attr_ulong(CKA_CERTIFICATE_TYPE, CKC_X_509) <<
368 pk11_attr_data(CKA_VALUE, i2d());
369
370 p11.startSession(slot, true);
371
372 QList<CK_OBJECT_HANDLE> objs = p11.objectList(p11_atts);
373 if (objs.count() != 0) {
374 XCA_WARN(tr("This certificate is already on the security token"));
375 return;
376 }
377
378 p11_atts <<
379 pk11_attr_bool(CKA_TOKEN, true) <<
380 pk11_attr_bool(CKA_PRIVATE, false) <<
381 pk11_attr_data(CKA_SUBJECT, getSubject().i2d()) <<
382 pk11_attr_data(CKA_ISSUER, getIssuerName().i2d()) <<
383 pk11_attr_data(CKA_SERIAL_NUMBER, getSerial().i2d()) <<
384 pk11_attr_data(CKA_LABEL, desc.toUtf8()) <<
385 (card ? card->getIdAttr() : p11.findUniqueID(CKO_CERTIFICATE));
386
387 if (p11.tokenLogin(p11.tokenInfo().label(), false).isNull())
388 return;
389
390 p11.createObject(p11_atts);
391 }
392
deleteFromToken()393 void pki_x509::deleteFromToken()
394 {
395 pki_key *privkey = getRefKey();
396 pki_scard *card = dynamic_cast<pki_scard *>(privkey);
397 slotidList p11_slots;
398
399 if (!card || !pkcs11::libraries.loaded())
400 return;
401
402 if (privkey && privkey->isToken()) {
403 slotid slot;
404 if (!card->prepare_card(&slot))
405 return;
406 p11_slots << slot;
407 } else {
408 pkcs11 p11;
409 p11_slots = p11.getSlotList();
410 }
411 for (int i=0; i<p11_slots.count(); i++) {
412 deleteFromToken(p11_slots[i]);
413 }
414 }
415
objectAttributes()416 pk11_attlist pki_x509::objectAttributes()
417 {
418 pk11_attlist attrs;
419 attrs <<
420 pk11_attr_ulong(CKA_CLASS, CKO_CERTIFICATE) <<
421 pk11_attr_ulong(CKA_CERTIFICATE_TYPE, CKC_X_509) <<
422 pk11_attr_data(CKA_VALUE, i2d());
423 return attrs;
424 }
425
deleteFromToken(const slotid & slot)426 void pki_x509::deleteFromToken(const slotid &slot)
427 {
428 pkcs11 p11;
429 p11.startSession(slot, true);
430
431 pk11_attlist atts = objectAttributes();
432 QList<CK_OBJECT_HANDLE> objs = p11.objectList(atts);
433 if (!objs.count())
434 return;
435
436 tkInfo ti = p11.tokenInfo();
437 if (!XCA_YESNO(tr("Delete the certificate '%1' from the token '%2 (#%3)'?").
438 arg(getIntName()).arg(ti.label()).arg(ti.serial())))
439 {
440 return;
441 }
442 if (p11.tokenLogin(ti.label(), false).isNull())
443 return;
444
445 p11.deleteObjects(objs);
446 }
447
renameOnToken(const slotid & slot,const QString & name)448 int pki_x509::renameOnToken(const slotid &slot, const QString &name)
449 {
450
451 pkcs11 p11;
452 p11.startSession(slot, true);
453 pk11_attlist attrs = objectAttributes();
454
455 QList<CK_OBJECT_HANDLE> objs = p11.objectList(attrs);
456 if (!objs.count())
457 return 0;
458
459 pk11_attr_data label(CKA_LABEL, name.toUtf8());
460 tkInfo ti = p11.tokenInfo();
461 if (p11.tokenLogin(ti.label(), false).isNull())
462 return 0;
463 p11.storeAttribute(label, objs[0]);
464 return 1;
465 }
466
setNotBefore(const a1time & a)467 void pki_x509::setNotBefore(const a1time &a)
468 {
469 a1time t(a);
470 X509_set_notBefore(cert, t.get_utc());
471 pki_openssl_error();
472 }
473
setNotAfter(const a1time & a)474 void pki_x509::setNotAfter(const a1time &a)
475 {
476 a1time t(a);
477 X509_set_notAfter(cert, t.get_utc());
478 pki_openssl_error();
479 }
480
getNotBefore() const481 a1time pki_x509::getNotBefore() const
482 {
483 a1time a(X509_get_notBefore(cert));
484 return a;
485 }
486
getNotAfter() const487 a1time pki_x509::getNotAfter() const
488 {
489 a1time a(X509_get_notAfter(cert));
490 return a;
491 }
492
getSubject() const493 x509name pki_x509::getSubject() const
494 {
495 x509name x(X509_get_subject_name(cert));
496 pki_openssl_error();
497 return x;
498 }
499
getIssuerName() const500 x509name pki_x509::getIssuerName() const
501 {
502 x509name x(X509_get_issuer_name(cert));
503 pki_openssl_error();
504 return x;
505 }
506
setSubject(const x509name & n)507 void pki_x509::setSubject(const x509name &n)
508 {
509 X509_set_subject_name(cert, n.get());
510 pki_openssl_error();
511 }
512
setIssuer(const x509name & n)513 void pki_x509::setIssuer(const x509name &n)
514 {
515 X509_set_issuer_name(cert, n.get());
516 pki_openssl_error();
517 }
518
addV3ext(const x509v3ext & e,bool skip_existing)519 bool pki_x509::addV3ext(const x509v3ext &e, bool skip_existing)
520 {
521 if (!e.isValid())
522 return false;
523 if (skip_existing && X509_get_ext_by_NID(cert, e.nid(), -1) != -1)
524 return false;
525 X509_EXTENSION *ext = e.get();
526 X509_add_ext(cert, ext, -1);
527 X509_EXTENSION_free(ext);
528 pki_openssl_error();
529 return true;
530 }
531
delSigner(pki_base * s)532 void pki_x509::delSigner(pki_base *s)
533 {
534 if (s && (s->getSqlItemId() == issuerSqlId))
535 issuerSqlId = QVariant();
536 }
537
isCA() const538 bool pki_x509::isCA() const
539 {
540 bool ca;
541 int crit;
542 BASIC_CONSTRAINTS *bc = (BASIC_CONSTRAINTS *)
543 X509_get_ext_d2i(cert, NID_basic_constraints, &crit, NULL);
544 pki_openssl_error();
545 ca = bc && bc->ca;
546 if (bc)
547 BASIC_CONSTRAINTS_free(bc);
548 return ca;
549 }
550
canSign() const551 bool pki_x509::canSign() const
552 {
553 pki_key *privkey = getRefKey();
554 if (!privkey || privkey->isPubKey())
555 return false;
556 if (privkey->isToken() && !pkcs11::libraries.loaded())
557 return false;
558 return isCA();
559 }
560
hasExtension(int nid) const561 bool pki_x509::hasExtension(int nid) const
562 {
563 return getV3ext().idxByNid(nid) != -1;
564 }
565
sign(pki_key * signkey,const EVP_MD * digest)566 void pki_x509::sign(pki_key *signkey, const EVP_MD *digest)
567 {
568 EVP_PKEY *tkey;
569 if (!signkey) {
570 my_error(tr("There is no key for signing !"));
571 }
572 tkey = signkey->decryptKey();
573 pki_openssl_error();
574 X509_sign(cert, tkey, digest);
575 pki_openssl_error();
576 EVP_PKEY_free(tkey);
577 pki_openssl_error();
578 }
579
fromData(const unsigned char * p,db_header_t * head)580 void pki_x509::fromData(const unsigned char *p, db_header_t *head)
581 {
582 int version, size;
583 bool isRevoked = false;
584
585 version = head->version;
586 size = head->len - sizeof(db_header_t);
587
588 QByteArray ba((const char*)p, size);
589
590 d2i(ba);
591 pki_openssl_error();
592 /* trust = */ db::intFromData(ba);
593 if (version < 4) {
594 a1time revoked;
595 isRevoked = db::boolFromData(ba);
596 revoked.d2i(ba);
597 pki_openssl_error();
598 if (isRevoked) {
599 revocation.setDate(revoked);
600 revocation.setSerial(getSerial());
601 }
602 }
603 pki_openssl_error();
604 /* Superflous CaSerial = */db::stringFromData(ba);
605 QString caTemplate = db::stringFromData(ba);
606 crlDays = db::intFromData(ba);
607 crlExpire.d2i(ba);
608 pki_openssl_error();
609 if (version > 1)
610 /* randomSerial = */ db::boolFromData(ba);
611 if (version > 2)
612 crlNumber.setHex(db::stringFromData(ba));
613 pki_openssl_error();
614 if (version > 2 && version < 4) {
615 // load own revocation info, to tell daddy about it
616 a1time invalDate;
617 QString revoke_reason = db::stringFromData(ba);
618 invalDate.d2i(ba);
619 pki_openssl_error();
620 if (isRevoked) {
621 revocation.setReason(revoke_reason);
622 revocation.setInvalDate(invalDate);
623 }
624 }
625 pki_openssl_error();
626 if (version > 3) {
627 fromDataRevList.fromBA(ba);
628 pki_openssl_error();
629 }
630 if (ba.count() > 0) {
631 my_error(tr("Wrong Size %1").arg(ba.count()));
632 }
633 pki_openssl_error();
634
635 XSqlQuery q;
636 SQL_PREPARE(q, "SELECT id FROM items WHERE name=? AND type=?");
637 q.bindValue(0, caTemplate);
638 q.bindValue(1, tmpl);
639 q.exec();
640 if (q.next())
641 caTemplateSqlId = q.value(0);
642 }
643
644
writeDefault(const QString & dirname) const645 void pki_x509::writeDefault(const QString &dirname) const
646 {
647 XFile file(get_dump_filename(dirname, ".crt"));
648 file.open_write();
649 writeCert(file, true);
650 }
651
writeCert(XFile & file,bool PEM) const652 void pki_x509::writeCert(XFile &file, bool PEM) const
653 {
654 if (!cert)
655 return;
656 if (PEM) {
657 PEM_file_comment(file);
658 PEM_write_X509(file.fp(), cert);
659 } else {
660 i2d_X509_fp(file.fp(), cert);
661 }
662 pki_openssl_error();
663 }
664
getIndexEntry()665 QString pki_x509::getIndexEntry()
666 {
667 QString flag = NULL;
668 bool revoked = isRevoked();
669
670 if (revoked)
671 flag = "R";
672 else if (checkDate())
673 flag = "V";
674 else
675 flag = "E";
676
677 return QString("%1\t%2\t%3\t%4\tunknown\t%5\n").arg(
678 flag, getNotAfter().toPlainUTC(),
679 revoked ? revocation.getDate().toPlainUTC() : "",
680 getSerial(),
681 QString(X509_NAME_oneline(getSubject().get(), NULL, 0)));
682 }
683
pem(BioByteArray & b,int)684 bool pki_x509::pem(BioByteArray &b, int)
685 {
686 return PEM_write_bio_X509(b, cert);
687 }
688
cmpIssuerAndSerial(pki_x509 * refcert)689 bool pki_x509::cmpIssuerAndSerial(pki_x509 *refcert)
690 {
691 bool ret = X509_issuer_and_serial_cmp(cert, refcert->cert);
692 pki_openssl_error();
693 return ret;
694
695 }
696
verify_only(const pki_x509 * signer) const697 bool pki_x509::verify_only(const pki_x509 *signer) const
698 {
699 const X509_NAME *subject = X509_get_subject_name(signer->cert);
700 const X509_NAME *issuer = X509_get_issuer_name(cert);
701 pki_openssl_error();
702 if (X509_NAME_cmp(subject, issuer)) {
703 return false;
704 }
705 EVP_PKEY *pub = X509_get_pubkey(signer->cert);
706 if (!pub) {
707 pki_ign_openssl_error();
708 return false;
709 }
710 int i = X509_verify(cert, pub);
711 EVP_PKEY_free(pub);
712 pki_ign_openssl_error();
713 return i>0;
714 }
715
verify(pki_x509 * signer)716 bool pki_x509::verify(pki_x509 *signer)
717 {
718 if (getSigner() || !signer)
719 return false;
720 if (signer == this &&
721 issuerSqlId == sqlItemId &&
722 issuerSqlId != QVariant())
723 return true;
724
725 if (signer && verify_only(signer)) {
726 int idx;
727 x509rev r;
728 x509revList rl(revocation);
729 r.setSerial(getSerial());
730 setSigner(signer);
731 signer->mergeRevList(rl);
732 rl = signer->getRevList();
733 idx = rl.indexOf(r);
734 if (idx != -1)
735 revocation = rl[idx];
736 return true;
737 }
738 return false;
739 }
740
getRevList() const741 x509revList pki_x509::getRevList() const
742 {
743 return isCA() ? x509revList::fromSql(sqlItemId) : x509revList();
744 }
745
mergeRevList(x509revList & l)746 void pki_x509::mergeRevList(x509revList &l)
747 {
748 x509revList revList = getRevList();
749 revList.merge(l);
750
751 if (revList.merged)
752 revList.sqlUpdate(sqlItemId);
753 }
754
setRevocations(const x509revList & rl)755 void pki_x509::setRevocations(const x509revList &rl)
756 {
757 x509rev rev;
758 x509revList revList = rl;
759
760 foreach(pki_base *p, childItems) {
761 pki_x509 *pki = static_cast<pki_x509 *>(p);
762 rev.setSerial(pki->getSerial());
763 int idx = revList.indexOf(rev);
764 if (idx != -1)
765 pki->revocation = revList[idx];
766 else
767 pki->revocation = x509rev();
768 }
769 revList.sqlUpdate(sqlItemId);
770 }
771
getPubKey() const772 pki_key *pki_x509::getPubKey() const
773 {
774 EVP_PKEY *pkey = X509_get_pubkey(cert);
775 pki_ign_openssl_error();
776 if (pkey == NULL)
777 return NULL;
778 pki_evp *key = new pki_evp(pkey);
779 pki_openssl_error();
780 return key;
781 }
782
compareNameAndKey(pki_x509 * other)783 bool pki_x509::compareNameAndKey(pki_x509 *other)
784 {
785 int r;
786 X509_NAME *s1, *s2;
787 EVP_PKEY *pub1, *pub2;
788
789 if (!cert || !other->cert)
790 return false;
791 s1 = X509_get_subject_name(cert);
792 s2 = X509_get_subject_name(other->cert);
793 pki_openssl_error();
794 if (!s1 || !s2)
795 return false;
796 /* X509_NAME_cmp returns 0 if they match */
797 r = X509_NAME_cmp(s1, s2);
798 pki_openssl_error();
799 if (r)
800 return false;
801 pub1 = X509_get_pubkey(cert);
802 pub2 = X509_get_pubkey(other->cert);
803 pki_ign_openssl_error();
804 if (!pub1 || !pub2)
805 return false;
806 /* EVP_PKEY_cmp() return 1 if the keys match */
807 r = EVP_PKEY_cmp(pub1, pub2);
808 pki_openssl_error();
809 return r == 1;
810 }
811
setPubKey(pki_key * key)812 void pki_x509::setPubKey(pki_key *key)
813 {
814 X509_set_pubkey(cert, key->getPubKey());
815 pki_openssl_error();
816 }
817
fingerprint(const EVP_MD * digest) const818 QString pki_x509::fingerprint(const EVP_MD *digest) const
819 {
820 return ::fingerprint(i2d_bytearray(I2D_VOID(i2d_X509), cert), digest);
821 }
822
checkDate()823 bool pki_x509::checkDate()
824 {
825 a1time n, b, a;
826
827 n = a1time::now(),
828 b = getNotBefore();
829 a = getNotAfter();
830 pki_openssl_error();
831
832 if (!a.isValid() || !b.isValid())
833 return false;
834 if (!a.isUndefined() && (a < n))
835 return false;
836 if (b > n)
837 return false;
838 pki_openssl_error();
839 return true;
840 }
841
getV3ext() const842 extList pki_x509::getV3ext() const
843 {
844 extList el;
845 el.setStack(X509_get0_extensions(cert));
846 return el;
847 }
848
getExtByNid(int nid) const849 x509v3ext pki_x509::getExtByNid(int nid) const
850 {
851 extList el = getV3ext();
852 int i = el.idxByNid(nid);
853
854 try {
855 pki_openssl_error();
856 } catch(errorEx &err) {
857 XCA_WARN(err.getString());
858 }
859 if (i == -1)
860 return x509v3ext();
861 return el[i];
862 }
863
sigAlg() const864 int pki_x509::sigAlg() const
865 {
866 return X509_get_signature_nid(cert);
867 }
868
getSigner()869 pki_x509 *pki_x509::getSigner()
870 {
871 return Store.lookupPki<pki_x509>(issuerSqlId);
872 }
873
isRevoked() const874 bool pki_x509::isRevoked() const
875 {
876 return revocation.isValid();
877 }
878
setRevoked(const x509rev & revok)879 void pki_x509::setRevoked(const x509rev &revok)
880 {
881 revocation = revok;
882 }
883
caAndPathLen(bool * ca,a1int * pathlen,bool * hasLen) const884 bool pki_x509::caAndPathLen(bool *ca, a1int *pathlen, bool *hasLen) const
885 {
886 x509v3ext e = getExtByNid(NID_basic_constraints);
887 if (e.nid() != NID_basic_constraints)
888 return false;
889 BASIC_CONSTRAINTS *bc = (BASIC_CONSTRAINTS *)e.d2i();
890 if (hasLen)
891 *hasLen = bc->pathlen ? true : false;
892 if (pathlen && bc->pathlen)
893 pathlen->set(bc->pathlen);
894 if (ca)
895 *ca = bc->ca;
896 BASIC_CONSTRAINTS_free(bc);
897 pki_openssl_error();
898 return true;
899 }
900
column_data(const dbheader * hd) const901 QVariant pki_x509::column_data(const dbheader *hd) const
902 {
903 switch (hd->id) {
904 case HD_cert_serial:
905 return QVariant(getSerial().toHex());
906 case HD_cert_md5fp:
907 return QVariant(fingerprint(EVP_md5()));
908 case HD_cert_sha1fp:
909 return QVariant(fingerprint(EVP_sha1()));
910 case HD_cert_sha256fp:
911 return QVariant(fingerprint(EVP_sha256()));
912 case HD_cert_ca: {
913 a1int len;
914 bool ca, haslen;
915 if (caAndPathLen(&ca, &len, &haslen)) {
916 if (ca && haslen)
917 return QVariant(len.toDec());
918 if (!ca)
919 return QVariant(tr("No"));
920 else
921 return QVariant(tr("Yes"));
922 }
923 break;
924 }
925 }
926 return pki_x509super::column_data(hd);
927 }
928
column_a1time(const dbheader * hd) const929 a1time pki_x509::column_a1time(const dbheader *hd) const
930 {
931 switch (hd->id) {
932 case HD_cert_notBefore:
933 return getNotBefore();
934 case HD_cert_notAfter:
935 return getNotAfter();
936 case HD_cert_revocation:
937 if (isRevoked())
938 return revocation.getDate();
939 break;
940 case HD_cert_crl_expire:
941 if (canSign())
942 return crlExpire;
943 break;
944 }
945 return pki_base::column_a1time(hd);
946 }
947
icsVEVENT() const948 QStringList pki_x509::icsVEVENT() const
949 {
950 return pki_base::icsVEVENT(getNotAfter(),
951 tr("Renew certificate: %1").arg(getIntName()),
952 tr("The XCA certificate '%1', issued on %2 "
953 "will expire on %3.\n"
954 "It is stored in the XCA database '%4'")
955 .arg(getIntName())
956 .arg(getNotBefore().toPretty())
957 .arg(getNotAfter().toPretty())
958 .arg(Database.name())
959 );
960 }
961
collect_properties(QMap<QString,QString> & prp) const962 void pki_x509::collect_properties(QMap<QString, QString> &prp) const
963 {
964 prp["Issuer"] = getIssuerName().oneLine(XN_FLAG_RFC2253);
965 prp["Serial"] = getSerial().toHex();
966 prp["CA"] = isCA() ? "Yes" : "No";
967 prp["Not Before"] = getNotBefore().toPretty();
968 prp["Not After"] = getNotAfter().toPretty();
969 prp["Self signed"] = verify_only(this) ? "Yes" : "No";
970 pki_x509super::collect_properties(prp);
971 }
972
print(BioByteArray & bba,enum print_opt opt) const973 void pki_x509::print(BioByteArray &bba, enum print_opt opt) const
974 {
975 pki_x509super::print(bba, opt);
976 switch (opt) {
977 case print_openssl_txt:
978 X509_print(bba, cert);
979 break;
980 case print_pem:
981 PEM_write_bio_X509(bba, cert);
982 break;
983 case print_coloured:
984 break;
985 }
986 }
987
icsVEVENT_ca() const988 QStringList pki_x509::icsVEVENT_ca() const
989 {
990 QStringList ics;
991 pki_crl *crl = NULL;
992
993 ics << icsVEVENT();
994 foreach(pki_base *p, childItems) {
995 pki_x509 *pki = static_cast<pki_x509 *>(p);
996 if (pki->getNotAfter() > a1time() && !isRevoked())
997 ics << pki->icsVEVENT();
998 }
999
1000 QList<pki_crl*> list = Store.sqlSELECTpki<pki_crl>(
1001 "SELECT item FROM crls WHERE issuer = ?",
1002 QList<QVariant>() << QVariant(sqlItemId));
1003
1004 /* Get latest CRL */
1005 foreach(pki_crl *pki, list) {
1006 if (!crl || crl->getNextUpdate() < pki->getNextUpdate())
1007 crl = pki;
1008 }
1009 if (crl)
1010 ics << crl->icsVEVENT();
1011
1012 return ics;
1013 }
1014
getIcon(const dbheader * hd) const1015 QVariant pki_x509::getIcon(const dbheader *hd) const
1016 {
1017 int pixnum = 0;
1018 bool ca;
1019 QStringList icon_names {
1020 ":validcertIco", ":validcertkeyIco",
1021 ":invalidcertIco", ":invalidcertkeyIco"
1022 };
1023 switch (hd->id) {
1024 case HD_cert_ca:
1025 if (!caAndPathLen(&ca, NULL, NULL))
1026 return QVariant();
1027 if (!ca)
1028 return QVariant();
1029 return QVariant(QPixmap(":doneIco"));
1030 case HD_internal_name:
1031 if (hasPrivKey())
1032 pixnum += 1;
1033 if (isRevoked())
1034 pixnum += 2;
1035 break;
1036 default:
1037 return pki_x509super::getIcon(hd);
1038 }
1039 return QVariant(QPixmap(icon_names[pixnum]));
1040 }
1041
visible() const1042 bool pki_x509::visible() const
1043 {
1044 if (pki_x509super::visible())
1045 return true;
1046 if (getIssuerName().search(limitPattern))
1047 return true;
1048 if (fingerprint(EVP_md5()).contains(limitPattern))
1049 return true;
1050 if (fingerprint(EVP_sha1()).contains(limitPattern))
1051 return true;
1052 if (fingerprint(EVP_sha256()).contains(limitPattern))
1053 return true;
1054 if (getSerial().toHex().contains(limitPattern))
1055 return true;
1056 return false;
1057 }
1058
bg_color(const dbheader * hd) const1059 QVariant pki_x509::bg_color(const dbheader *hd) const
1060 {
1061 #define BG_RED QBrush(QColor(255, 0, 0))
1062 #define BG_YELLOW QBrush(QColor(255,255, 0))
1063 #define BG_CYAN QBrush(QColor(127,255,212))
1064
1065 if (Settings["no_expire_colors"])
1066 return QVariant();
1067
1068 QString unit, cert_expiry_num = Settings["cert_expiry"];
1069 unit = cert_expiry_num.right(1);
1070 cert_expiry_num.chop(1);
1071 int n = cert_expiry_num.toInt();
1072
1073 a1time nb, na, now, certwarn;
1074
1075 nb = getNotBefore();
1076 na = getNotAfter();
1077 now = a1time::now();
1078
1079 if (unit == "%") {
1080 quint64 lifetime = nb.secsTo(na);
1081 certwarn = nb.addSecs(lifetime *n /100);
1082 } else if (unit == "D") {
1083 certwarn = na.addDays(-n);
1084 } else if (unit == "W") {
1085 certwarn = na.addDays(-n*7);
1086 }
1087 switch (hd->id) {
1088 case HD_cert_notBefore:
1089 if (nb > now || !nb.isValid() || nb.isUndefined())
1090 return QVariant(BG_RED);
1091 break;
1092 case HD_cert_notAfter: {
1093 if (na.isUndefined())
1094 return QVariant(BG_CYAN);
1095 if (na < now)
1096 return QVariant(BG_RED);
1097 if (certwarn < now)
1098 return QVariant(BG_YELLOW);
1099 break;
1100 }
1101 case HD_cert_crl_expire:
1102 if (canSign()) {
1103 QDateTime crlwarn, crlex;
1104 crlex = crlExpire;
1105 if (!crlExpire.isUndefined()) {
1106 crlwarn = crlex.addSecs(-2 *60*60*24);
1107 if (crlex < now)
1108 return QVariant(BG_RED);
1109 if (crlwarn < now || !crlex.isValid())
1110 return QVariant(BG_YELLOW);
1111 }
1112 }
1113 }
1114 return QVariant();
1115 }
1116