1 /* vi: set sw=4 ts=4:
2 *
3 * Copyright (C) 2001 - 2014 Christian Hohnstaedt.
4 *
5 * All rights reserved.
6 */
7
8 #include "db_x509.h"
9 #include "pki_x509.h"
10 #include "pki_crl.h"
11 #include "pki_temp.h"
12 #include "pki_pkcs12.h"
13 #include "pki_pkcs7.h"
14 #include "pki_evp.h"
15 #include "pki_scard.h"
16 #include "pass_info.h"
17 #include "database_model.h"
18 #include "entropy.h"
19
20 #include "widgets/XcaWarning.h"
21 #include "widgets/CertExtend.h"
22 #include "widgets/ExportDialog.h"
23 #include "widgets/MainWindow.h"
24 #include "widgets/PwDialog.h"
25 #include "widgets/RevocationList.h"
26 #include "widgets/NewX509.h"
27 #include "widgets/Help.h"
28
29 #include "ui_CaProperties.h"
30 #include <QMessageBox>
31 #include <QContextMenuEvent>
32 #include <QAction>
33
34 #include <openssl/rand.h>
35
db_x509()36 db_x509::db_x509() : db_x509super("certificates")
37 {
38 sqlHashTable = "certs";
39 pkitype << x509;
40 pkitype_depends << x509_req;
41 updateHeaders();
42 loadContainer();
43 }
44
loadContainer()45 void db_x509::loadContainer()
46 {
47 db_x509super::loadContainer();
48
49 XSqlQuery q("SELECT item, issuer FROM certs WHERE issuer is NOT NULL");
50 while (q.next()) {
51 pki_base *root = treeItem;
52 pki_x509 *cert = Store.lookupPki<pki_x509>(q.value(0));
53 pki_x509 *issuer = Store.lookupPki<pki_x509>(q.value(1));
54 if (cert && issuer) {
55 cert->setSigner(issuer);
56 if (cert != issuer)
57 root = issuer;
58 }
59 if (cert && cert->getParent() != root) {
60 qDebug() << "MOVE" << cert->getIntName()
61 << "from" << cert->getParent()->getIntName()
62 << "to" << root->getIntName();
63 insertChild(cert, root);
64 }
65 }
66 emit columnsContentChanged();
67 }
68
getHeaders()69 dbheaderList db_x509::getHeaders()
70 {
71 dbheaderList h = db_x509super::getHeaders();
72 h << new dbheader(HD_cert_ca, true, tr("CA"),
73 tr("reflects the basic Constraints extension")) <<
74 new num_dbheader(HD_cert_serial, true, tr("Serial")) <<
75 new num_dbheader(HD_cert_md5fp, false,tr("MD5 fingerprint")) <<
76 new num_dbheader(HD_cert_sha1fp,false,tr("SHA1 fingerprint")) <<
77 new num_dbheader(HD_cert_sha256fp,false,tr("SHA256 fingerprint")) <<
78 new date_dbheader(HD_cert_notBefore, false,tr("Start date"),
79 tr("Not before")) <<
80 new date_dbheader(HD_cert_notAfter, true, tr("Expiry date"),
81 tr("Not after")) <<
82 new date_dbheader(HD_cert_revocation,false, tr("Revocation")) <<
83 new date_dbheader(HD_cert_crl_expire,true, tr("CRL Expiration"));
84 return h;
85 }
86
newPKI(enum pki_type type)87 pki_base *db_x509::newPKI(enum pki_type type)
88 {
89 (void)type;
90 return new pki_x509();
91 }
92
getAllIssuers()93 QList<pki_x509 *> db_x509::getAllIssuers()
94 {
95 /* Select X509 CA certificates with available private key */
96 return Store.sqlSELECTpki<pki_x509>(
97 "SELECT x509super.item FROM x509super "
98 "JOIN private_keys ON x509super.pkey = private_keys.item "
99 "JOIN certs ON certs.item = x509super.item "
100 "WHERE certs.ca=1") +
101 Store.sqlSELECTpki<pki_x509>(
102 "SELECT x509super.item FROM x509super "
103 "JOIN tokens ON x509super.pkey = tokens.item "
104 "JOIN certs ON certs.item = x509super.item "
105 "WHERE certs.ca=1");
106 }
107
remFromCont(const QModelIndex & idx)108 void db_x509::remFromCont(const QModelIndex &idx)
109 {
110 db_crl *crls = Database.model<db_crl>();
111 db_x509super::remFromCont(idx);
112 pki_base *pki = fromIndex(idx);
113 pki_x509 *child;
114 pki_base *new_parent;
115 QList<pki_x509 *> childs;
116
117 while (pki->childCount()) {
118 child = dynamic_cast<pki_x509*>(pki->takeFirst());
119 child->delSigner(dynamic_cast<pki_x509*>(pki));
120 new_parent = child->findIssuer();
121 insertChild(child);
122 if (new_parent)
123 childs << child;
124 }
125 XSqlQuery q;
126 SQL_PREPARE(q, "UPDATE certs SET issuer=? WHERE item=?");
127 foreach(pki_x509 *child, childs) {
128 q.bindValue(0, child->getSigner()->getSqlItemId());
129 q.bindValue(1, child->getSqlItemId());
130 AffectedItems(child->getSqlItemId());
131 q.exec();
132 }
133 crls->removeSigner(pki);
134 }
135
recursiveSigning(pki_x509 * cert,pki_x509 * client)136 static bool recursiveSigning(pki_x509 *cert, pki_x509 *client)
137 {
138 /* recursive signing check */
139 for (pki_x509 *s = cert->getSigner(); s; s = s->getSigner()) {
140 if (s == s->getSigner()) {
141 return false;
142 }
143 if (s == client) {
144 qWarning() << "Recursive signing:" << s->getIntName()
145 << "<->" << cert->getIntName();
146 return true;
147 }
148 }
149 return false;
150 }
151
inToCont(pki_base * pki)152 void db_x509::inToCont(pki_base *pki)
153 {
154 pki_x509 *cert = dynamic_cast<pki_x509*>(pki);
155 cert->setParent(NULL);
156 pki_base *root = cert->getSigner();
157
158 insertChild(cert, root);
159
160 QList<pki_x509 *> childs;
161 QList<pki_x509 *> items;
162 unsigned pubhash = cert->pubHash();
163 unsigned namehash = cert->getSubject().hashNum();
164 x509revList revList;
165
166 /* Search for another certificate (name and key)
167 * and use its childs if we are newer */
168 items = Store.sqlSELECTpki<pki_x509>(
169 "SELECT x509super.item FROM x509super "
170 "JOIN certs ON certs.item = x509super.item "
171 "WHERE certs.ca=1 AND x509super.subj_hash=? "
172 "AND x509super.key_hash=?",
173 QList<QVariant>() << namehash << pubhash);
174 foreach(pki_x509 *other, items) {
175 if (other == cert)
176 continue;
177 if (!other->compareNameAndKey(cert))
178 continue;
179 if (cert->getNotAfter() < other->getNotAfter())
180 continue;
181 foreach(pki_base *b, other->getChildItems()) {
182 pki_x509 *child = dynamic_cast<pki_x509*>(b);
183 if (!child)
184 continue;
185 child->delSigner(other);
186 childs << child;
187 }
188 revList.merge(other->getRevList());
189 }
190 /* Search rootItem childs, whether they are ours */
191 foreach(pki_base *b, rootItem->getChildItems()) {
192 pki_x509 *child = dynamic_cast<pki_x509*>(b);
193 if (!child || child == cert || child->getSigner() == child)
194 continue;
195 if (child->verify_only(cert))
196 childs << child;
197 }
198 /* move collected childs to us */
199 XSqlQuery q;
200 x509revList revokedChilds;
201 SQL_PREPARE(q, "UPDATE certs SET issuer=? WHERE item=?");
202 q.bindValue(0, cert->getSqlItemId());
203 foreach(pki_x509 *child, childs) {
204 if (recursiveSigning(cert, child))
205 continue;
206 if (!child->verify(cert))
207 continue;
208 insertChild(child, cert);
209 q.bindValue(1, child->getSqlItemId());
210 AffectedItems(child->getSqlItemId());
211 q.exec();
212 XCA_SQLERROR(q.lastError());
213 if (child->isRevoked())
214 revokedChilds << child->getRevocation();
215 }
216 q.finish();
217 revList.merge(revokedChilds);
218 cert->setRevocations(revList);
219
220 /* Update CRLs */
221 QList<pki_crl *> crls = Store.sqlSELECTpki<pki_crl>(
222 "SELECT item FROM crls WHERE iss_hash=?",
223 QList<QVariant>() << namehash);
224 SQL_PREPARE(q, "UPDATE crls SET issuer=? WHERE item=?");
225 foreach(pki_crl *crl, crls) {
226 crl->verify(cert);
227 if (cert != crl->getIssuer())
228 continue;
229 q.bindValue(0, cert->getSqlItemId());
230 q.bindValue(1, crl->getSqlItemId());
231 AffectedItems(crl->getSqlItemId());
232 q.exec();
233 XCA_SQLERROR(q.lastError());
234 }
235 }
236
getCerts(bool unrevoked)237 QList<pki_x509*> db_x509::getCerts(bool unrevoked)
238 {
239 QList<pki_x509*> c;
240 c.clear();
241 foreach(pki_x509 *pki, Store.getAll<pki_x509>()) {
242 if (unrevoked && pki->isRevoked())
243 continue;
244 c.append(pki);
245 }
246 return c;
247 }
248
writeIndex(const QString & fname,bool hierarchy) const249 void db_x509::writeIndex(const QString &fname, bool hierarchy) const
250 {
251 if (hierarchy) {
252 QString dir = fname + "/";
253 if (!QDir().mkpath(fname)) {
254 throw errorEx(tr("Failed to create directory '%1'")
255 .arg(fname));
256 }
257 QList<pki_x509*> issuers = Store.sqlSELECTpki<pki_x509>(
258 "SELECT DISTINCT issuer FROM certs WHERE issuer != item");
259 foreach(pki_x509 *ca, issuers) {
260 XFile file(dir + ca->getUnderlinedName() + ".txt");
261 file.open_write();
262 writeIndex(file, Store.sqlSELECTpki<pki_x509>(
263 "SELECT item FROM certs WHERE issuer=?",
264 QList<QVariant>()<<QVariant(ca->getSqlItemId()))
265 );
266 }
267 } else {
268 XFile file(fname);
269 file.open_write();
270 writeIndex(file, Store.sqlSELECTpki<pki_x509>(
271 "SELECT item FROM certs"));
272 }
273 }
274
randomSerial()275 static a1int randomSerial()
276 {
277 unsigned char buf[SHA512_DIGEST_LENGTH];
278 unsigned char md[SHA512_DIGEST_LENGTH];
279
280 Entropy::seed_rng();
281
282 RAND_bytes(buf, SHA512_DIGEST_LENGTH);
283 SHA512(buf, SHA512_DIGEST_LENGTH, md);
284 a1int serial;
285 if (md[0] && md[0] < 0x80)
286 serial.setRaw(md, (int)Settings["serial_len"] / 8);
287 return serial;
288 }
289
getUniqueSerial(pki_x509 * signer)290 a1int db_x509::getUniqueSerial(pki_x509 *signer)
291 {
292 // returns an unused unique serial
293 a1int serial, signer_serial;
294 x509rev rev;
295 x509revList revList;
296 if (signer) {
297 signer_serial = signer->getSerial();
298 revList = signer->getRevList();
299 }
300 for (int i=0; ; i++) {
301 if (i > 100)
302 throw errorEx(tr("Failed to retrieve unique random serial"));
303 serial = randomSerial();
304 if (serial == a1int(0L))
305 continue;
306 if (!signer)
307 break;
308 if (signer_serial == serial)
309 continue;
310 rev.setSerial(serial);
311 if (revList.contains(rev))
312 continue;
313 if (signer->getBySerial(serial))
314 continue;
315 break;
316 }
317 return serial;
318 }
319
insert(pki_base * item)320 pki_base *db_x509::insert(pki_base *item)
321 {
322 pki_x509 *cert = dynamic_cast<pki_x509 *>(item);
323 pki_x509 *oldcert = dynamic_cast<pki_x509 *>(getByReference(cert));
324 if (oldcert) {
325 XCA_INFO(tr("The certificate already exists in the database as:\n'%1'\nand so it was not imported").arg(oldcert->getIntName()));
326 delete cert;
327 return NULL;
328 }
329 return insertPKI(cert);
330 }
331
load(void)332 void db_x509::load(void)
333 {
334 load_cert c;
335 load_default(c);
336 }
337
get1SelectedCert()338 pki_x509 *db_x509::get1SelectedCert()
339 {
340 QModelIndexList indexes = mainwin->certView->getSelectedIndexes();
341 QModelIndex index;
342 if (indexes.count())
343 index = indexes[0];
344 return fromIndex<pki_x509>(index);
345 }
346
markRequestSigned(pki_x509req * req,pki_x509 * cert)347 void db_x509::markRequestSigned(pki_x509req *req, pki_x509 *cert)
348 {
349 if (!req || !cert)
350 return;
351 pki_x509 *issuer = cert->getSigner();
352
353 Transaction;
354 if (!TransBegin())
355 return;
356
357 XSqlQuery q;
358 req->setDone();
359 SQL_PREPARE(q, "UPDATE requests SET signed=? WHERE item=?");
360 q.bindValue(0, 1);
361 q.bindValue(1, req->getSqlItemId());
362 AffectedItems(req->getSqlItemId());
363 q.exec();
364
365 a1time a;
366 req->selfComment(tr("Signed on %1 by '%2'").arg(a.toPretty())
367 .arg(issuer ? issuer->getIntName() : tr("Unknown")));
368 SQL_PREPARE(q, "UPDATE items SET comment=? WHERE id=?");
369 q.bindValue(0, req->getComment());
370 q.bindValue(1, req->getSqlItemId());
371 q.exec();
372
373 TransCommit();
374 }
375
newItem()376 void db_x509::newItem()
377 {
378 NewX509 *dlg = new NewX509();
379 dlg->setCert();
380 pki_x509 *sigcert = get1SelectedCert();
381 dlg->defineSigner((pki_x509*)sigcert, true);
382 if (dlg->exec()) {
383 newCert(dlg);
384 }
385 delete dlg;
386 }
387
newCert(pki_x509req * req)388 void db_x509::newCert(pki_x509req *req)
389 {
390 NewX509 *dlg = new NewX509();
391 pki_x509 *sigcert = get1SelectedCert();
392 dlg->setCert();
393 dlg->defineRequest(req);
394 dlg->defineSigner(sigcert, true);
395 if (dlg->exec()) {
396 newCert(dlg);
397 }
398 delete dlg;
399 }
400
newCert(pki_temp * temp)401 void db_x509::newCert(pki_temp *temp)
402 {
403 NewX509 *dlg = new NewX509();
404 dlg->setCert();
405 dlg->defineTemplate(temp);
406 if (dlg->exec()) {
407 newCert(dlg);
408 }
409 delete dlg;
410 }
411
newCert(pki_x509 * cert)412 void db_x509::newCert(pki_x509 *cert)
413 {
414 NewX509 *dlg = new NewX509();
415 dlg->setCert();
416 dlg->fromX509super(cert, false);
417 if (dlg->exec()) {
418 newCert(dlg);
419 }
420 delete dlg;
421 }
422
newCert(NewX509 * dlg)423 pki_x509 *db_x509::newCert(NewX509 *dlg)
424 {
425 pki_x509 *cert = NULL;
426 pki_x509 *signcert = NULL;
427 pki_x509req *req = NULL;
428 pki_key *signkey = NULL, *clientkey = NULL, *tempkey = NULL;
429 a1int serial;
430 QString intname;
431
432 try {
433 Transaction;
434 // Step 1 - Subject and key
435 if (!dlg->fromReqCB->isChecked()) {
436 clientkey = dlg->getSelectedKey();
437 if (!clientkey)
438 return NULL;
439 intname = dlg->description->text();
440 } else {
441 // A PKCS#10 Request was selected
442 req = dlg->getSelectedReq();
443 if (!req)
444 return NULL;
445 clientkey = req->getRefKey();
446 if (clientkey == NULL) {
447 clientkey = req->getPubKey();
448 tempkey = clientkey;
449 }
450 intname = req->getIntName();
451 }
452 TransThrow();
453
454 if (clientkey == NULL)
455 throw errorEx(tr("Invalid public key"));
456 // initially create cert
457 cert = new pki_x509();
458 cert->setIntName(intname);
459 cert->setSubject(dlg->getX509name());
460 cert->setPubKey(clientkey);
461
462 // Step 2 - select Signing
463 if (dlg->foreignSignRB->isChecked()) {
464 signcert = dlg->getSelectedSigner();
465 if (!signcert) {
466 delete cert;
467 return NULL;
468 }
469 serial = getUniqueSerial(signcert);
470 signkey = signcert->getRefKey();
471 } else {
472 signcert = cert;
473 signkey = clientkey;
474 serial = getUniqueSerial(NULL);
475 }
476
477 dlg->initCtx(cert, signcert, NULL);
478 // if we can not sign
479 if (! signkey || signkey->isPubKey()) {
480 delete cert;
481 throw errorEx(tr("The key you selected for signing is not a private one."));
482 }
483
484 // set the issuers name
485 cert->setIssuer(signcert->getSubject());
486 cert->setSerial(serial);
487
488 // Step 3 - Choose the Date
489 // Date handling
490 cert->setNotBefore(dlg->notBefore->getDate());
491 a1time a;
492 if (dlg->noWellDefinedExpDate->isChecked())
493 a.setUndefined();
494 else
495 a = dlg->notAfter->getDate();
496
497 cert->setNotAfter(a);
498
499 // STEP 4 handle extensions
500
501 // apply all extensions to the subject cert in the context
502 dlg->getAllExt();
503
504 // apply extensions from CSR if requested
505 if (dlg->copyReqExtCB->isChecked() && dlg->fromReqCB->isChecked()) {
506 extList el = req->getV3ext();
507 int m = el.count();
508 for (int i=0; i<m; i++)
509 cert->addV3ext(el[i], true);
510 }
511
512 const EVP_MD *hashAlgo = dlg->hashAlgo->currentHash();
513 // and finally sign the request
514 cert->sign(signkey, hashAlgo);
515
516 // set the comment field
517 cert->setComment(dlg->comment->toPlainText());
518 cert->pkiSource = dlg->getPkiSource();
519 cert = dynamic_cast<pki_x509*>(insert(cert));
520 createSuccess(cert);
521 if (cert && clientkey->isToken()) {
522 pki_scard *card = (pki_scard*)clientkey;
523 if (XCA_YESNO(tr("Store the certificate to the key on the token '%1 (#%2)' ?").
524 arg(card->getCardLabel()).arg(card->getSerial())))
525 {
526 try {
527 cert->store_token(false);
528 } catch (errorEx &err) {
529 XCA_ERROR(err);
530 }
531 }
532 }
533 delete tempkey;
534 markRequestSigned(req, cert);
535 TransCommit();
536 }
537
538 catch (errorEx &err) {
539 XCA_ERROR(err);
540 delete cert;
541 if (tempkey != NULL)
542 delete(tempkey);
543 cert = NULL;
544 }
545 return cert;
546 }
547
store(QModelIndex idx)548 void db_x509::store(QModelIndex idx)
549 {
550 QModelIndexList l;
551 l << idx;
552 store(l);
553 }
554
store(QModelIndexList list)555 void db_x509::store(QModelIndexList list)
556 {
557 QStringList filt;
558 bool chain;
559 QList<exportType> types, usual;
560
561 if (list.size() == 0)
562 return;
563
564 pki_x509 *oldcrt, *crt = fromIndex<pki_x509>(list[0]);
565 if (!crt)
566 return;
567
568 pki_key *privkey = crt->getRefKey();
569 pki_evp *pkey;
570 chain = crt->getSigner() && crt->getSigner() != crt;
571
572 usual <<
573 exportType(exportType::PEM, "crt", "PEM") <<
574 exportType(exportType::PKCS7, "p7b", "PKCS #7");
575
576 types << exportType(exportType::DER, "cer", "DER");
577
578 if (list.size() > 1) {
579 usual <<
580 exportType(exportType::PEM_selected, "pem",
581 "PEM selected") <<
582 exportType(exportType::PKCS7_selected, "pem",
583 "PKCS7 selected");
584 }
585 if (chain) {
586 types <<
587 exportType(exportType::PEM_chain, "pem",
588 tr("PEM chain")) <<
589 exportType(exportType::PKCS7_chain, "p7b",
590 tr("PKCS#7 chain"));
591 }
592
593 if (privkey && privkey->isPrivKey() && !privkey->isToken()) {
594 if (chain) {
595 usual << exportType(exportType::PKCS12_chain, "pfx",
596 tr("PKCS#12 chain"));
597 types << exportType(exportType::PKCS12, "pfx",
598 "PKCS #12");
599 } else {
600 usual << exportType(exportType::PKCS12, "pfx",
601 "PKCS #12");
602 }
603 types <<
604 exportType(exportType::PEM_cert_key, "pem",
605 tr("PEM + key")) <<
606 exportType(exportType::PEM_cert_pk8, "pem",
607 "PEM + PKCS#8");
608 }
609 types << exportType() <<
610 exportType(exportType::PKCS7_unrevoked, "p7b",
611 tr("PKCS#7 unrevoked")) <<
612 exportType(exportType::PKCS7_all, "p7b",
613 tr("PKCS#7 all")) <<
614 exportType(exportType::PEM_unrevoked, "pem",
615 tr("PEM unrevoked")) <<
616 exportType(exportType::PEM_all, "pem",
617 tr("PEM all")) <<
618 exportType(exportType::Index, "txt",
619 tr("Certificate Index file"));
620 if (crt->getNotAfter() > a1time())
621 types << exportType(exportType::vcalendar, "ics",
622 tr("vCalendar"));
623
624 if (crt->isCA())
625 types << exportType(exportType::vcalendar_ca, "ics",
626 tr("CA vCalendar"));
627
628 types = usual << exportType() << types;
629 ExportDialog *dlg = new ExportDialog(NULL, tr("Certificate export"),
630 tr("X509 Certificates ( *.pem *.cer *.crt *.p12 *.pfx *.p7b )"), crt,
631 QPixmap(":certImg"), types, "certexport");
632 if (!dlg->exec()) {
633 delete dlg;
634 return;
635 }
636 QStringList vcal;
637 QList<pki_x509*> certs;
638 QList<pki_base*> items;
639 enum exportType::etype type = dlg->type();
640 try {
641 XFile file(dlg->filename->text());
642 file.open_write();
643 pki_base::pem_comment = dlg->pemComment->isChecked();
644
645 switch (type) {
646 case exportType::PEM:
647 crt->writeCert(file, true);
648 break;
649 case exportType::PEM_chain:
650 while (crt && crt != oldcrt) {
651 crt->writeCert(file, true);
652 oldcrt = crt;
653 crt = crt->getSigner();
654 }
655 break;
656 case exportType::PEM_selected:
657 foreach(QModelIndex idx, list) {
658 crt = fromIndex<pki_x509>(idx);
659 if (crt)
660 crt->writeCert(file, true);
661 }
662 break;
663 case exportType::PEM_unrevoked:
664 foreach(pki_x509 *pki, Store.getAll<pki_x509>()) {
665 if (!pki->isRevoked())
666 pki->writeCert(file, true);
667 }
668 break;
669 case exportType::PEM_all:
670 foreach(pki_x509 *pki, Store.getAll<pki_x509>()) {
671 pki->writeCert(file, true);
672 }
673 break;
674 case exportType::DER:
675 crt->writeCert(file, false);
676 break;
677 case exportType::PKCS7:
678 case exportType::PKCS7_chain:
679 case exportType::PKCS7_unrevoked:
680 case exportType::PKCS7_selected:
681 case exportType::PKCS7_all:
682 writePKCS7(crt, file, type, list);
683 break;
684 case exportType::PKCS12:
685 writePKCS12(crt, file, false);
686 break;
687 case exportType::PKCS12_chain:
688 writePKCS12(crt, file, true);
689 break;
690 case exportType::PEM_cert_pk8:
691 case exportType::PEM_cert_key:
692 pkey = (pki_evp *)crt->getRefKey();
693 if (!pkey || pkey->isPubKey()) {
694 XCA_WARN(tr("There was no key found for the Certificate: '%1'").
695 arg(crt->getIntName()));
696 break;
697 }
698 if (pkey->isToken()) {
699 XCA_WARN(tr("Not possible for a token key: '%1'").
700 arg(crt->getIntName()));
701 break;
702 }
703
704 if (type == exportType::PEM_cert_pk8) {
705 pkey->writePKCS8(file, EVP_des_ede3_cbc(),
706 PwDialog::pwCallback, true);
707 } else {
708 pkey->writeKey(file, NULL, NULL, true);
709 }
710 crt->writeCert(file, true);
711 break;
712 case exportType::Index:
713 foreach(QModelIndex idx, list) {
714 crt = fromIndex<pki_x509>(idx);
715 if (crt)
716 certs << crt;
717 }
718 writeIndex(file, certs);
719 break;
720 case exportType::vcalendar:
721 foreach(QModelIndex idx, list) {
722 crt = fromIndex<pki_x509>(idx);
723 if (crt)
724 vcal += crt->icsVEVENT();
725 }
726 writeVcalendar(file, vcal);
727 break;
728 case exportType::vcalendar_ca:
729 foreach(QModelIndex idx, list) {
730 crt = fromIndex<pki_x509>(idx);
731 if (crt)
732 vcal += crt->icsVEVENT_ca();
733 }
734 writeVcalendar(file, vcal);
735 break;
736 default:
737 exit(1);
738 }
739 }
740 catch (errorEx &err) {
741 XCA_ERROR(err);
742 }
743 pki_base::pem_comment = false;
744 delete dlg;
745 }
746
writeIndex(XFile & file,QList<pki_x509 * > items) const747 void db_x509::writeIndex(XFile &file, QList<pki_x509*> items) const
748 {
749 QString index;
750 foreach(pki_x509 *cert, items) {
751 if (cert)
752 index += cert->getIndexEntry();
753 }
754 file.write(index.toUtf8());
755 }
756
writePKCS12(pki_x509 * cert,XFile & file,bool chain) const757 void db_x509::writePKCS12(pki_x509 *cert, XFile &file, bool chain) const
758 {
759 QStringList filt;
760 pki_pkcs12 *p12 = NULL;
761 try {
762 pki_evp *privkey = (pki_evp *)cert->getRefKey();
763 if (!privkey || privkey->isPubKey()) {
764 XCA_WARN(tr("There was no key found for the Certificate: '%1'").arg(cert->getIntName()));
765 return;
766 }
767 if (privkey->isToken()) {
768 XCA_WARN(tr("Not possible for the token-key Certificate '%1'").arg(cert->getIntName()));
769 return;
770 }
771 p12 = new pki_pkcs12(cert->getIntName(), cert, privkey);
772 pki_x509 *signer = cert->getSigner();
773 while ((signer != NULL ) && (signer != cert) && chain) {
774 p12->append_item(signer);
775 cert = signer;
776 signer = signer->getSigner();
777 }
778 p12->writePKCS12(file);
779 }
780 catch (errorEx &err) {
781 XCA_ERROR(err);
782 }
783 delete p12;
784 }
785
writePKCS7(pki_x509 * cert,XFile & file,exportType::etype type,QModelIndexList list) const786 void db_x509::writePKCS7(pki_x509 *cert, XFile &file, exportType::etype type,
787 QModelIndexList list) const
788 {
789 pki_pkcs7 *p7 = NULL;
790
791 try {
792 p7 = new pki_pkcs7(QString());
793 switch (type) {
794 case exportType::PKCS7_chain:
795 while (cert != NULL) {
796 p7->append_item(cert);
797 if (cert->getSigner() == cert)
798 cert = NULL;
799 else
800 cert = cert->getSigner();
801 }
802 break;
803 case exportType::PKCS7:
804 p7->append_item(cert);
805 break;
806 case exportType::PKCS7_selected:
807 foreach(QModelIndex idx, list) {
808 cert = fromIndex<pki_x509>(idx);
809 if (cert)
810 p7->append_item(cert);
811 }
812 break;
813 case exportType::PKCS7_unrevoked:
814 case exportType::PKCS7_all:
815 foreach(pki_x509 *cer, Store.getAll<pki_x509>()) {
816 if ((type == exportType::PKCS7_all) ||
817 (!cer->isRevoked()))
818 p7->append_item(cer);
819 }
820 break;
821 default:
822 exit(1);
823 }
824 p7->writeP7(file, false);
825 }
826 catch (errorEx &err) {
827 XCA_ERROR(err);
828 }
829 delete p7;
830 }
831
certRenewal(QModelIndexList indexes)832 void db_x509::certRenewal(QModelIndexList indexes)
833 {
834 pki_x509 *oldcert = NULL, *signer = NULL, *newcert =NULL;
835 pki_key *signkey = NULL;
836 a1time time;
837 a1int serial;
838 CertExtend *dlg = NULL;
839 x509rev r;
840 bool doRevoke = false;
841
842 if (indexes.size() == 0)
843 return;
844 QModelIndex idx = indexes[0];
845
846 try {
847 oldcert = fromIndex<pki_x509>(idx);
848 if (!oldcert || !(signer = oldcert->getSigner()) ||
849 !(signkey = signer->getRefKey()) ||
850 signkey->isPubKey())
851 return;
852 bool renew_myself = signer == oldcert;
853 CertExtend *dlg = new CertExtend(NULL,
854 renew_myself ? NULL : signer);
855 dlg->revoke->setEnabled(!renew_myself);
856 if (!dlg->exec()) {
857 delete dlg;
858 return;
859 }
860 if (dlg->revoke->isChecked() && !renew_myself) {
861 Revocation *revoke = new Revocation(indexes);
862 doRevoke = revoke->exec();
863 r = revoke->getRevocation();
864 delete revoke;
865 }
866 foreach(idx, indexes) {
867 oldcert = fromIndex<pki_x509>(idx);
868 if (!oldcert)
869 continue;
870 newcert = new pki_x509(oldcert);
871 newcert->pkiSource = renewed;
872 serial = dlg->keepSerial->isChecked() ?
873 oldcert->getSerial() : getUniqueSerial(signer);
874 newcert->setRevoked(x509rev());
875
876 // change date and serial
877 newcert->setSerial(serial);
878 newcert->setNotBefore(dlg->notBefore->getDate());
879 a1time a;
880 if (dlg->noWellDefinedExpDate->isChecked())
881 a.setUndefined();
882 else
883 a = dlg->notAfter->getDate();
884
885 newcert->setNotAfter(a);
886
887 // and finally sign the cert
888 newcert->sign(signkey, oldcert->getDigest());
889 newcert = dynamic_cast<pki_x509 *>(insert(newcert));
890 createSuccess(newcert);
891 }
892 if (doRevoke)
893 do_revoke(indexes, r);
894 }
895 catch (errorEx &err) {
896 XCA_ERROR(err);
897 delete newcert;
898 }
899 delete dlg;
900 emit columnsContentChanged();
901 }
902
903
revoke(QModelIndexList indexes)904 void db_x509::revoke(QModelIndexList indexes)
905 {
906 if (indexes.size() == 0)
907 return;
908 Revocation *revoke = new Revocation(indexes);
909 if (revoke->exec()) {
910 do_revoke(indexes, revoke->getRevocation());
911 }
912 emit columnsContentChanged();
913 }
914
do_revoke(QModelIndexList indexes,const x509rev & r)915 void db_x509::do_revoke(QModelIndexList indexes, const x509rev &r)
916 {
917 pki_x509 *parent = NULL, *cert, *iss;
918 x509revList revlist;
919
920 foreach(QModelIndex idx, indexes) {
921 cert = fromIndex<pki_x509>(idx);
922 if (!cert)
923 continue;
924 iss = cert->getSigner();
925 if (parent == NULL) {
926 parent = iss;
927 } else if (parent != iss) {
928 parent = NULL;
929 break;
930 }
931 }
932 if (!parent) {
933 qWarning("%s(%d): Certs have different/no signer",
934 __func__, __LINE__);
935 }
936 foreach(QModelIndex idx, indexes) {
937 cert = fromIndex<pki_x509>(idx);
938 if (!cert)
939 continue;
940 x509rev rev(r);
941 rev.setSerial(cert->getSerial());
942 cert->setRevoked(rev);
943 revlist << rev;
944 }
945 parent->mergeRevList(revlist);
946 }
947
unRevoke(QModelIndexList indexes)948 void db_x509::unRevoke(QModelIndexList indexes)
949 {
950 pki_x509 *parent = NULL;
951 x509revList revList;
952
953 foreach(QModelIndex idx, indexes) {
954 pki_x509 *cert = fromIndex<pki_x509>(idx);
955 if (!cert)
956 continue;
957 pki_x509 *iss = cert->getSigner();
958 if (parent == NULL) {
959 parent = iss;
960 } else if (parent != iss) {
961 parent = NULL;
962 break;
963 }
964 }
965 if (!parent) {
966 qWarning("%s(%d): Certs have different/no issuer\n",
967 __func__, __LINE__);
968 return;
969 }
970 revList = parent->getRevList();
971
972 foreach(QModelIndex idx, indexes) {
973 int i;
974 x509rev rev;
975 pki_x509 *cert = fromIndex<pki_x509>(idx);
976
977 if (!cert)
978 continue;
979
980 cert->setRevoked(x509rev());
981 rev.setSerial(cert->getSerial());
982 i = revList.indexOf(rev);
983 if (i != -1)
984 revList.takeAt(i);
985 }
986 parent->setRevocations(revList);
987 emit columnsContentChanged();
988 }
989
toCertificate(QModelIndex index)990 void db_x509::toCertificate(QModelIndex index)
991 {
992 pki_x509 *cert = fromIndex<pki_x509>(index);
993 if (!cert)
994 return;
995 if (!cert->getRefKey() && cert->getSigner() != cert)
996 extractPubkey(index);
997 cert->pkiSource = transformed;
998 newCert(cert);
999 }
1000
toRequest(QModelIndex idx)1001 void db_x509::toRequest(QModelIndex idx)
1002 {
1003 db_x509req *reqs = Database.model<db_x509req>();
1004 pki_x509 *cert = fromIndex<pki_x509>(idx);
1005 if (!cert)
1006 return;
1007
1008 try {
1009 pki_x509req *req = new pki_x509req();
1010 check_oom(req);
1011 req->pkiSource = transformed;
1012 req->setIntName(cert->getIntName());
1013 req->createReq(cert->getRefKey(), cert->getSubject(),
1014 cert->getDigest(), cert->getV3ext());
1015 createSuccess(reqs->insert(req));
1016 }
1017 catch (errorEx &err) {
1018 XCA_ERROR(err);
1019 }
1020 }
1021
toToken(QModelIndex idx,bool alwaysSelect)1022 void db_x509::toToken(QModelIndex idx, bool alwaysSelect)
1023 {
1024 pki_x509 *cert = fromIndex<pki_x509>(idx);
1025 if (!cert)
1026 return;
1027 try {
1028 cert->store_token(alwaysSelect);
1029 } catch (errorEx &err) {
1030 XCA_ERROR(err);
1031 }
1032 }
1033
caProperties(QModelIndex idx)1034 void db_x509::caProperties(QModelIndex idx)
1035 {
1036 QStringList actions;
1037 Ui::CaProperties ui;
1038
1039 pki_x509 *cert = fromIndex<pki_x509>(idx);
1040 if (!cert)
1041 return;
1042
1043 QDialog *dlg = new QDialog(NULL);
1044 ui.setupUi(dlg);
1045 ui.days->setSuffix(QString(" ") + tr("days"));
1046 ui.days->setMaximum(1000000);
1047 ui.days->setValue(cert->getCrlDays());
1048 ui.image->setPixmap(QPixmap(":certImg"));
1049
1050 QVariant tmplId = cert->getTemplateSqlId();
1051 pki_temp *templ = Store.lookupPki<pki_temp>(tmplId);
1052
1053 ui.temp->insertPkiItems(Store.getAll<pki_temp>());
1054 ui.temp->setNullItem(tr("No template"));
1055 ui.temp->setCurrentIndex(0);
1056 if (templ)
1057 ui.temp->setCurrentPkiItem(templ);
1058
1059 ui.certName->setTitle(cert->getIntName());
1060 mainwin->helpdlg->register_ctxhelp_button(dlg, "ca_properties");
1061
1062 if (dlg->exec()) {
1063 XSqlQuery q;
1064 QSqlError e;
1065 Transaction;
1066 TransThrow();
1067
1068 templ = ui.temp->currentPkiItem();
1069 tmplId = templ ? templ->getSqlItemId() : QVariant();
1070
1071 cert->setTemplateSqlId(tmplId);
1072 cert->setCrlDays(ui.days->value());
1073
1074 SQL_PREPARE(q, "UPDATE authority SET crlDays=?, "
1075 "template=? WHERE item=?");
1076
1077 q.bindValue(0, cert->getCrlDays());
1078 q.bindValue(1, tmplId);
1079 q.bindValue(2, cert->getSqlItemId());
1080 AffectedItems(cert->getSqlItemId());
1081 q.exec();
1082 TransDone(q.lastError());
1083 XCA_SQLERROR(q.lastError());
1084 }
1085 delete dlg;
1086 }
1087