/* vi: set sw=4 ts=4: * * Copyright (C) 2001 - 2009 Christian Hohnstaedt. * * All rights reserved. */ #include "NewX509.h" #include #include #include #include #include #include #include #include #include #include "MainWindow.h" #include "v3ext.h" #include "lib/x509name.h" #include "lib/db_key.h" #include "lib/db_x509req.h" #include "lib/db_x509.h" #include "lib/db_temp.h" #include "lib/oid.h" #include "lib/func.h" int NewX509::name_nid[] = { NID_countryName, NID_stateOrProvinceName, NID_localityName, NID_organizationName, NID_organizationalUnitName, NID_commonName, NID_pkcs9_emailAddress }; NewX509::NewX509(QWidget *parent) :QDialog(parent) { int i; eku_nid = *MainWindow::eku_nid; dn_nid = *MainWindow::dn_nid; aia_nid = *MainWindow::aia_nid; attr_nid << NID_pkcs9_unstructuredName << NID_pkcs9_challengePassword; QStringList sl; setupUi(this); /* temporary storage for creating temporary X509V3_CTX */ ctx_cert = NULL; sl << "Type" << "Content"; extDNlist->setColumnCount(2); extDNlist->setHorizontalHeaderLabels(sl); setWindowTitle(tr(XCA_TITLE)); nsImg->setPixmap(*MainWindow::nsImg); //setFont( tFont ); serialNr->setValidator( new QRegExpValidator(QRegExp("[0-9a-fA-F]*"), this)); QStringList strings; // are there any useable private keys ? newKeyDone(""); // any PKCS#10 requests to be used ? strings = MainWindow::reqs->getDesc(); if (strings.isEmpty()) { fromReqCB->setDisabled(true); fromReqCB->setChecked(false); } else { reqList->insertItems(0, strings); } on_fromReqCB_clicked(); // How about signing certificates ? strings = MainWindow::certs->getSignerDesc(); if (strings.isEmpty()) { foreignSignRB->setDisabled(true); } else { certList->insertItems(0, strings); } #ifdef WG_QA_SERIAL selfQASignRB = new QRadioButton(signerBox); setTabOrder(serialNr, selfQASignRB); setTabOrder(selfQASignRB, foreignSignRB); selfQASignRB->setText(tr( "Create a &self signed certificate with a MD5-hashed QA serial")); QBoxLayout *l = (QBoxLayout *)signerBox->layout(); l->insertWidget(1, selfQASignRB); #endif // set dates to now and now + 1 year a1time a; validNumber->setText("1"); validRange->setCurrentIndex(2); on_applyTime_clicked(); // settings for the templates .... strings.clear(); strings = MainWindow::temps->getDescPredefs(); tempList->insertItems(0, strings); // setup Extended keyusage for (i=0; i < eku_nid.count(); i++) ekeyUsage->addItem(OBJ_nid2ln(eku_nid[i])); // setup Distinguished Name for (i=0; i < dn_nid.count(); i++) extDNobj->addItem(OBJ_nid2ln(dn_nid[i])); // setup Authority Info Access for (i=0; i < aia_nid.count(); i++) aiaOid->addItem(OBJ_nid2ln(aia_nid[i])); // init the X509 v3 context X509V3_set_ctx(&ext_ctx, NULL , NULL, NULL, NULL, 0); X509V3_set_ctx_nodb(&ext_ctx); // setup the list of x509nameEntrys name_ptr[0] = countryName; name_ptr[1] = stateOrProvinceName; name_ptr[2] = localityName; name_ptr[3] = organisationName; name_ptr[4] = organisationalUnitName; name_ptr[5] = commonName; name_ptr[6] = emailAddress; // Setup Request Attributes if (attrWidget->layout()) delete attrWidget->layout(); QGridLayout *attrLayout = new QGridLayout(attrWidget); attrLayout->setAlignment(Qt::AlignTop); attrLayout->setSpacing(6); attrLayout->setMargin(0); attr_edit.clear(); for (i=0; i < attr_nid.count(); i++) { QLabel *label; QLineEdit *edit; int nid = attr_nid[i]; label = new QLabel(this); label->setText(QString(OBJ_nid2ln(nid))); label->setToolTip(QString(OBJ_nid2sn(nid))); edit = new QLineEdit(this); attr_edit << edit; attrLayout->addWidget(label, i, 0); attrLayout->addWidget(edit, i, 1); } // last polish on_certList_currentIndexChanged(0); certList->setDisabled(true); tabWidget->setCurrentIndex(0); attrWidget->hide(); pt = none; } void NewX509::setRequest() { reqWidget->hide(); attrWidget->show(); signerBox->setEnabled(false); timewidget->setEnabled(false); capt->setText(tr("Create Certificate signing request")); authKey->setEnabled(false); setImage(MainWindow::csrImg); pt = x509_req; } NewX509::~NewX509() { if (ctx_cert) delete(ctx_cert); } void NewX509::addReqAttributes(pki_x509req *req) { for (int i=0; i < attr_nid.count(); i++) { req->addAttribute(attr_nid[i], attr_edit[i]->text()); } } void NewX509::setTemp(pki_temp *temp) { QString text = tr("Create"); if (temp->getIntName() != "--") { description->setText(temp->getIntName()); description->setDisabled(true); text = tr("Edit"); } capt->setText(text + " " + tr("XCA template")); tabWidget->removeTab(0); privKeyBox->setEnabled(false); validityBox->setEnabled(false); setImage(MainWindow::tempImg); pt = tmpl; } void NewX509::setCert() { capt->setText(tr("Create x509 Certificate")); setImage(MainWindow::certImg); pt = x509; } void NewX509::setImage(QPixmap *img) { image->setPixmap(*img); } void NewX509::defineTemplate(pki_temp *temp) { fromTemplate(temp); templateChanged(temp); tempList->setEnabled(false); } void NewX509::defineRequest(pki_x509req *req) { if (!req) return; fromReqCB->setEnabled(true); fromReqCB->setChecked(true); QString reqname = req->getIntName(); reqList->setCurrentIndex(reqList->findText(reqname)); on_fromReqCB_clicked(); } void NewX509::defineSigner(pki_x509 *defcert) { int index; // suggested from: Andrey Brindeew if (defcert && defcert->canSign() ) { QString name = defcert->getIntName(); foreignSignRB->setChecked(true); certList->setEnabled(true); if ((index = certList->findText(name)) >= 0) { certList->setCurrentIndex(index); } if (!defcert->getTemplate().isEmpty()) { on_applyTemplate_clicked(); } } } static int lb2int(QListWidget *lb) { int i, x=0, c=lb->count(); QListWidgetItem *item; for (i=0; iitem(i); if (lb->isItemSelected(item)){ x |= 1<count(); QListWidgetItem *item; for (i=0; iitem(i); lb->setItemSelected(item, (1< items; for (int i=0; ifindItems(lname, Qt::MatchExactly); if (items.size() > 0) lb->setItemSelected(items[0], 1); } } static QString lb2QString(QListWidget *lb) { QStringList sl; for (int i=0; icount(); i++) { QListWidgetItem *item = lb->item(i); if (lb->isItemSelected(item)) { sl << QString(OBJ_ln2sn(CCHAR(item->text()))); } } return sl.join(", "); } void NewX509::fromTemplate(pki_temp *temp) { setX509name(temp->xname); subAltName->setText(temp->subAltName); issAltName->setText(temp->issAltName); crlDist->setText(temp->crlDist); setAuthInfAcc_string(temp->authInfAcc); nsComment->setText(temp->nsComment); nsBaseUrl->setText(temp->nsBaseUrl); nsRevocationUrl->setText(temp->nsRevocationUrl); nsCARevocationUrl->setText(temp->nsCARevocationUrl); nsRenewalUrl->setText(temp->nsRenewalUrl); nsCaPolicyUrl->setText(temp->nsCaPolicyUrl); nsSslServerName->setText(temp->nsSslServerName); int2lb(nsCertType, temp->nsCertType); basicCA->setCurrentIndex(temp->ca); bcCritical->setChecked(temp->bcCrit); kuCritical->setChecked(temp->keyUseCrit); ekuCritical->setChecked(temp->eKeyUseCrit); subKey->setChecked(temp->subKey); authKey->setChecked(temp->authKey); int2lb(keyUsage, temp->keyUse); QString2lb(ekeyUsage, temp->eKeyUse); validNumber->setText(QString::number(temp->validN)); validRange->setCurrentIndex(temp->validM); midnightCB->setChecked(temp->validMidn); basicPath->setText(temp->pathLen); nconf_data->document()->setPlainText(temp->adv_ext); noWellDefinedExpDate->setChecked(temp->noWellDefined); notBefore->setNow(); on_applyTime_clicked(); } void NewX509::toTemplate(pki_temp *temp) { temp->setIntName(description->text()); temp->xname = getX509name(); temp->subAltName = subAltName->text(); temp->issAltName = issAltName->text(); temp->crlDist = crlDist->text(); temp->authInfAcc = getAuthInfAcc_string(); temp->nsComment = nsComment->text(); temp->nsBaseUrl = nsBaseUrl->text(); temp->nsRevocationUrl = nsRevocationUrl->text(); temp->nsCARevocationUrl = nsCARevocationUrl->text(); temp->nsRenewalUrl = nsRenewalUrl->text(); temp->nsCaPolicyUrl = nsCaPolicyUrl->text(); temp->nsSslServerName = nsSslServerName->text(); temp->nsCertType = lb2int(nsCertType); temp->ca = basicCA->currentIndex(); temp->bcCrit = bcCritical->isChecked(); temp->keyUseCrit = kuCritical->isChecked(); temp->eKeyUseCrit = ekuCritical->isChecked(); temp->subKey = subKey->isChecked(); temp->authKey = authKey->isChecked(); temp->keyUse = lb2int(keyUsage); temp->eKeyUse = lb2QString(ekeyUsage); temp->validN = validNumber->text().toInt(); temp->validM = validRange->currentIndex(); temp->pathLen = QString::number(basicPath->text().toInt()); temp->validMidn = midnightCB->isChecked(); if (nconf_data->isReadOnly()) { temp->adv_ext = v3ext_backup; } else { temp->adv_ext = nconf_data->toPlainText(); } temp->noWellDefined = noWellDefinedExpDate->isChecked(); } void NewX509::on_fromReqCB_clicked() { bool request = fromReqCB->isChecked(); bool subj_tab_present = tabWidget->widget(1) == tab_1; bool subChange = reqSubChange->isChecked(); if (request && subj_tab_present && !subChange) tabWidget->removeTab(1); else if ((!request || subChange) && !subj_tab_present) tabWidget->insertTab(1, tab_1, tr("Subject")); reqList->setEnabled(request); copyReqExtCB->setEnabled(request); showReqBut->setEnabled(request); reqSubChange->setEnabled(request); switchHashAlgo(); } void NewX509::on_reqSubChange_clicked() { if (reqSubChange->isChecked()) { pki_x509req *req = getSelectedReq(); description->setText(req->getIntName()); setX509name(req->getSubject()); usedKeysToo->setEnabled(false); keyList->setEnabled(false); genKeyBut->setEnabled(false); } on_fromReqCB_clicked(); } void NewX509::on_keyList_currentIndexChanged(const QString &) { switchHashAlgo(); } void NewX509::on_reqList_currentIndexChanged(const QString &) { switchHashAlgo(); } void NewX509::switchHashAlgo() { pki_key *key; pki_x509super *sig; if (foreignSignRB->isChecked()) sig = getSelectedSigner(); else if (fromReqCB->isChecked()) sig = getSelectedReq(); else sig = NULL; key = sig ? sig->getRefKey() : getSelectedKey(); if (key) { hashAlgo->setKeyType(key->getKeyType()); hashAlgo->setupHashes(key->possibleHashNids()); } else { hashAlgo->setKeyType(EVP_PKEY_RSA); hashAlgo->setupAllHashes(); } } void NewX509::on_showReqBut_clicked() { QString req = reqList->currentText(); emit showReq(req); } void NewX509::on_genKeyBut_clicked() { QString name = description->text(); if (name.isEmpty()) name = commonName->text(); if (name.isEmpty()) name = emailAddress->text(); emit genKey(name); } void NewX509::on_certList_currentIndexChanged(int) { a1time snb, sna; pki_x509 *cert = getSelectedSigner(); switchHashAlgo(); if (!cert) return; QString templ = cert->getTemplate(); snb = cert->getNotBefore(); sna = cert->getNotAfter(); if (snb > notBefore->getDate()) notBefore->setDate(snb); if (sna < notAfter->getDate()) notAfter->setDate(sna); if (templ.isEmpty()) return; templateChanged(templ); } void NewX509::templateChanged(QString tempname) { int index; if (!tempList->isEnabled()) return; if ((index = tempList->findText(tempname)) <0) return; tempList->setCurrentIndex(index); } void NewX509::templateChanged(pki_temp *templ) { QString tempname = templ->getIntName(); templateChanged(tempname); } void NewX509::on_applyTemplate_clicked() { pki_temp *temp = NULL; if (!tempList->isEnabled()) return; QString name = tempList->currentText(); if (name.isEmpty()) return; temp = (pki_temp *)MainWindow::temps->getByName(name); if (!temp) return; fromTemplate(temp); } void NewX509::on_foreignSignRB_toggled(bool checked) { switchHashAlgo(); certList->setEnabled(checked); } void NewX509::on_selfSignRB_toggled(bool checked) { serialNr->setEnabled(checked); } void NewX509::newKeyDone(QString name) { QStringList keys; private_keys = MainWindow::keys->get0PrivateDesc(true); private_keys0 = MainWindow::keys->get0PrivateDesc(false); keyList->clear(); if (usedKeysToo->isChecked()) keys = private_keys; else keys = private_keys0; keyList->insertItems(0, keys); if (name.isEmpty() && keys.count() >0) name = keys[0]; keyList->setCurrentIndex(keys.indexOf(name)); } void NewX509::on_noWellDefinedExpDate_toggled(bool) { notAfter->setEnabled(!noWellDefinedExpDate->isChecked()); } void NewX509::on_usedKeysToo_toggled(bool) { QString cur = keyList->currentText(); QStringList keys; keyList->clear(); if (usedKeysToo->isChecked()) keys = private_keys; else keys = private_keys0; keyList->insertItems(0, keys); keyList->setCurrentIndex(keys.indexOf(cur)); } pki_key *NewX509::getSelectedKey() { QString name = pki_key::removeTypeFromIntName(keyList->currentText()); return (pki_key *)MainWindow::keys->getByName(name); } pki_x509 *NewX509::getSelectedSigner() { return (pki_x509 *)MainWindow::certs->getByName(certList->currentText()); } pki_x509req *NewX509::getSelectedReq() { return (pki_x509req *)MainWindow::reqs->getByName(reqList->currentText()); } x509name NewX509::getX509name(int _throw) { x509name x; int j, row, nid; try { for (j = 0; jtext()); } row = extDNlist->rowCount(); for (j=0; jitem(j,0)->text())); x.addEntryByNid(nid, extDNlist->item(j,1)->text()); } } catch (errorEx &err) { if (!err.isEmpty()) { if (_throw) throw err; else QMessageBox::warning(this, XCA_TITLE, err.getString()); } } return x; } void NewX509::setX509name(const x509name &n) { int i,j; #if QT_VERSION >= 0x040200 extDNlist->clearContents(); #else extDNlist->clear(); #endif for (j=0; jsetText(""); } for (i=0, j=0; i< n.entryCount(); i++) { int nid = n.nid(i); QStringList sl = n.entryList(i); for ( ; jtext().isEmpty()) { name_ptr[j]->setText(sl[2]); break; } } if (j == EXPLICIT_NAME_CNT) { QTableWidgetItem *tw; int row; row = extDNlist->rowCount(); extDNlist->setRowCount(row+1); for (int i=0; i<2; i++) { tw = new QTableWidgetItem(sl[i+1]); extDNlist->setItem(row, i, tw); } } } } void NewX509::on_extDNadd_clicked() { QTableWidgetItem *tw; int row; row = extDNlist->rowCount(); extDNlist->setRowCount(row+1); tw = new QTableWidgetItem(extDNobj->currentText()); extDNlist->setItem(row, 0, tw); tw = new QTableWidgetItem(extDNname->text()); extDNlist->setItem(row, 1, tw); } void NewX509::on_extDNdel_clicked() { extDNlist->removeRow(extDNlist->currentRow()); } void NewX509::on_applyTime_clicked() { applyTD(this, validNumber->text().toInt(), validRange->currentIndex(), midnightCB->isChecked(), notBefore, notAfter); } void NewX509::setupTmpCtx() { pki_x509 *signcert; pki_x509req *req = NULL; a1int serial; QString errtxt; // initially create temporary ctx cert if (ctx_cert) delete(ctx_cert); ctx_cert = new pki_x509(); if (fromReqCB->isChecked()) { req = getSelectedReq(); ctx_cert->setSubject(req->getSubject()); } else { ctx_cert->setSubject(getX509name()); } // Step 2 - select Signing if (foreignSignRB->isChecked()) { signcert = getSelectedSigner(); serial = signcert->getCaSerial(); } else { signcert = ctx_cert; ctx_cert->setIssuer(ctx_cert->getSubject()); serial.setHex(serialNr->text()); } ctx_cert->setSerial(serial); initCtx(ctx_cert, signcert, req); } void NewX509::editV3ext(QLineEdit *le, QString types, int n) { v3ext *dlg; dlg = new v3ext(this); setupTmpCtx(); dlg->addInfo(le, types.split(',' ), n, &ext_ctx); dlg->exec(); delete(dlg); } void NewX509::on_adv_validate_clicked() { if (!nconf_data->isReadOnly()) { QString errtxt; extList el; pki_base::ign_openssl_error(); QString result; setupTmpCtx(); v3ext_backup = nconf_data->toPlainText(); if (fromReqCB->isChecked() && copyReqExtCB->isChecked()) { el = getSelectedReq()->getV3ext(); } if (el.size() > 0) { result = "

" "From PKCS#10 request

\n"; result += el.getHtml("
"); } el = getGuiExt(); el += getNetscapeExt(); el.delInvalid(); if (el.size() > 0) { if (!result.isEmpty()) result += "\n


\n"; result += "

Other Tabs

\n"; result += el.getHtml("
"); } el = getAdvanced(); if (el.size() > 0) { if (!result.isEmpty()) result += "\n


\n"; result += "

Advanced Tab

\n"; result += el.getHtml("
"); } while (int i = ERR_get_error() ) { errtxt += ERR_error_string(i, NULL); errtxt += "
\n"; } if (!errtxt.isEmpty()) { if (!result.isEmpty()) result += "\n


\n"; result += "

Errors

\n"; result += errtxt; } nconf_data->document()->setHtml(result); nconf_data->setReadOnly(true); adv_validate->setText(tr("Edit")); valid_htmltext = result; checkExtDuplicates(); } else { nconf_data->document()->setPlainText(v3ext_backup); nconf_data->setReadOnly(false); adv_validate->setText(tr("Validate")); valid_htmltext = ""; } pki_base::ign_openssl_error(); } void NewX509::on_editSubAlt_clicked() { QString s = "email,RID,URI,DNS,IP,otherName"; if (pt != x509_req) s = QString("email:copy,") + s; editV3ext(subAltName, s, NID_subject_alt_name); } void NewX509::on_editIssAlt_clicked() { QString s = "email,RID,URI,DNS,IP,otherName"; if (pt != x509_req) s = QString("issuer:copy,") +s ; editV3ext(issAltName, s, NID_issuer_alt_name); } void NewX509::on_editCrlDist_clicked() { editV3ext(crlDist, "URI", NID_crl_distribution_points); } void NewX509::on_editAuthInfAcc_clicked() { editV3ext(authInfAcc, "email,RID,URI,DNS,IP", NID_info_access); } void NewX509::on_tabWidget_currentChanged(int) { /* reset advanced tab to editable text */ if (nconf_data->isReadOnly()) on_adv_validate_clicked(); } QString NewX509::mandatoryDnRemain() { QStringList dnl = MainWindow::mandatory_dn.split(","); x509name n; int i; if (fromReqCB->isChecked() && !reqSubChange->isChecked()) n = getSelectedReq()->getSubject(); else n = getX509name(); for (i=0; i< n.entryCount(); i++) { int j = dnl.indexOf(QString(OBJ_nid2sn(n.nid(i)))); if (j>=0) dnl.removeAt(j); } return dnl.join(","); } void NewX509::on_okButton_clicked() { on_tabWidget_currentChanged(0); try { getX509name(1); } catch (errorEx &err) { if (QMessageBox::warning(this, tr(XCA_TITLE), err.getString(), tr("Ok"), tr("Abort rollout")) == 1) { reject(); } return; } if (fromReqCB->isChecked()) { if (!getSelectedReq()->verify()) { if (QMessageBox::warning(this, tr(XCA_TITLE), tr("The verification of the Certificate request failed.\n" "The rollout should be aborted."), tr("Continue anyway"), tr("Abort rollout")) == 1) { reject(); } } } if (description->text().isEmpty() && !fromReqCB->isChecked()) { if (commonName->text().isEmpty()) { if (QMessageBox::warning(this, tr(XCA_TITLE), tr("The internal name and the common name are empty.\n" "Please set at least the internal name."), tr("Ok"), tr("Abort rollout")) == 1) { reject(); } return; } else { description->setText(commonName->text()); } } if ( keyList->count() == 0 && keyList->isEnabled() && !fromReqCB->isChecked()) { if (QMessageBox::warning(this, tr(XCA_TITLE), tr("There is no Key selected for signing."), tr("Ok"), tr("Abort rollout")) == 1) { reject(); } return; } QString unsetDN; if (pt != tmpl) unsetDN = mandatoryDnRemain(); if (!unsetDN.isEmpty()) { switch (QMessageBox::warning(this, tr(XCA_TITLE), tr("The following distinguished name entries are empty,\n" "though you have declared them as mandatory " "in the options menu:\n") + unsetDN, tr("Ok"), tr("Abort rollout"), tr("Continue rollout"))) { case -1: case 0: return; case 1: reject(); return; } } if (notBefore->getDate() > notAfter->getDate() && !noWellDefinedExpDate->isChecked()) { switch (QMessageBox::warning(this, tr(XCA_TITLE), tr("The certificate will be out of date before it becomes valid. " "You most probably mixed up both dates."), tr("Ok"), tr("Abort rollout"), tr("Continue rollout"))) { case -1: case 0: return; case 1: reject(); return; } } on_adv_validate_clicked(); if (checkExtDuplicates()) { switch (QMessageBox::warning(this, tr(XCA_TITLE), tr("The certificate contains duplicated extensions. " "Check the validation on the advanced tab."), tr("Ok"), tr("Abort rollout"), tr("Continue rollout"))) { case -1: case 0: return; case 1: reject(); return; } } accept(); }