/* vi: set sw=4 ts=4: */ /* * Copyright (C) 2001 Christian Hohnstaedt. * * All rights reserved. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the author nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * This program links to software with different licenses from: * * http://www.openssl.org which includes cryptographic software * written by Eric Young (eay@cryptsoft.com)" * * http://www.sleepycat.com * * http://www.trolltech.com * * * * http://www.hohnstaedt.de/xca * email: christian@hohnstaedt.de * * $Id$ * */ #include "NewX509.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "MainWindow.h" #include "validity.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_commonName, NID_countryName, NID_localityName, NID_stateOrProvinceName, NID_organizationName, NID_organizationalUnitName, NID_pkcs9_emailAddress }; NewX509::NewX509(QWidget *parent , const char *name, bool modal, WFlags f) :NewX509_UI(parent, name, modal, f) { unsigned int i; connect( extDNadd, SIGNAL(clicked()), this, SLOT(addX509NameEntry()) ); connect( extDNdel, SIGNAL(clicked()), this, SLOT(delX509NameEntry()) ); eku_nid = *MainWindow::eku_nid; dn_nid = *MainWindow::dn_nid; aia_nid = *MainWindow::aia_nid; setCaption(tr(XCA_TITLE)); fixtemp = NULL; nsImg->setPixmap(*MainWindow::nsImg); #ifndef qt3 // pretty fat Title :-) QFont tFont;// = getFont(); tFont.setPointSize(14); tFont.setBold(true); tFont.setUnderline(true); //setFont( tFont ); #else //setFont( tFont ); serialNr->setValidator( new QRegExpValidator(QRegExp("[0-9a-fA-F]*"), this)); #endif QStringList strings; // are there any useable private keys ? strings = MainWindow::keys->get0PrivateDesc(); keyList->insertStringList(strings); hashAlgo->setCurrentItem(1); // any PKCS#10 requests to be used ? strings = MainWindow::reqs->getDesc(); if (strings.isEmpty()) { fromReqCB->setDisabled(true); reqList->setDisabled(true); } else { reqList->insertStringList(strings); } // How about signing certificates ? strings = MainWindow::certs->getSignerDesc(); if (strings.isEmpty()) { foreignSignRB->setDisabled(true); certList->setDisabled(true); } else { certList->insertStringList(strings); } // set dates to now and now + 1 year a1time a; notBefore->setDate(a.now()); notAfter->setDate(a.now(60*60*24*365)); // settings for the templates .... strings = MainWindow::temps->getDesc(); strings.prepend(tr("Server Template")); strings.prepend(tr("Client Template")); strings.prepend(tr("CA Template")); strings.prepend(tr("Empty Template")); tempList->insertStringList(strings); // setup Extended keyusage for (i=0; i < eku_nid.count(); i++) ekeyUsage->insertItem(OBJ_nid2ln(eku_nid[i])); // setup Distinguished Name for (i=0; i < dn_nid.count(); i++) extDNobj->insertItem(OBJ_nid2ln(dn_nid[i])); // setup Authority Info Access for (i=0; i < aia_nid.count(); i++) aiaOid->insertItem(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] = commonName; name_ptr[1] = countryName; name_ptr[2] = localityName; name_ptr[3] = stateOrProvinceName; name_ptr[4] = organisationName; name_ptr[5] = organisationalUnitName; name_ptr[6] = emailAddress; // last polish setFinishEnabled(page7,true); setNextEnabled(page2,false); signerChanged(); checkAuthKeyId(); } void NewX509::setRequest() { // setAppropriate(page4, false); // setAppropriate(page5, false); // setAppropriate(page6, false); finishButton()->setEnabled(true); changeDefault->setEnabled(true); changeDefault->setChecked(true); signerBox->setEnabled(false); requestBox->setEnabled(false); timeRangeBox->setEnabled(false); validitybox->setEnabled(false); startText_h=tr("Welcome to the settings for certificate signing requests."); startText_b=tr("A signing request needs a private key, so it will be " "created if there isn't any unused key available in the key " "database. This signing request can then be given to a " "Certification authority while the private key of the request " "and of the resulting certificate returned from the CA does never " "leave your computer."); endText=tr("You are done with entering all parameters for generating " "a Certificate signing request. The resulting request should " "be exported and send to an appropriate CA for signing it."); tText=tr("Certificate signing request"); setup(); setImage(MainWindow::csrImg); } NewX509::~NewX509() { } void NewX509::setTemp(pki_temp *temp) { setAppropriate(page1, false); finishButton()->setEnabled(true); startText_h=tr("Welcome to the settings for Templates."); startText_b=tr("This templates do not refer to any ASN.1 structure " "but are used to keep default settings for signing requests and " "certificates. When creating a Request or Certificate the template " "can preset the needed fields with default settings."); endText=tr("You are done with entering all parameters for the Template.\n" "After this step the template can be assigned to one of your CAs to " "be autoatically applied when signing with this CA."); tText=tr("Template"); if (temp->getIntName() != "--") { description->setText(temp->getIntName()); tText += tr(" change"); } setup(); privKeyBox->setEnabled(false); validitybox->setEnabled(false); setImage(MainWindow::tempImg); } void NewX509::setCert() { finishButton()->setEnabled(true); startText_h=tr("Welcome to the settings for Certificates."); startText_b=tr("The information for the new Certificate can either be " "grabbed from a given Certificate-request or be filled in by hand. " "In the case of not signing a request there needs to be at least one " "unused key. If this is not the case it will be created. If you want " "to self-sign a request (unusual but nevertheless possible) you need " "the private key used to create the request."); endText=tr("You are done with entering all parameters for creating " "a Certificate."); tText=tr("Certificate"); setup(); setImage(MainWindow::certImg); } void NewX509::setImage(QPixmap *image) { bigImg1->setPixmap(*image); bigImg2->setPixmap(*image); bigImg3->setPixmap(*image); bigImg4->setPixmap(*image); bigImg5->setPixmap(*image); bigImg6->setPixmap(*image); } void NewX509::setup() { startLabel_h->setText(startText_h); startLabel_b->setText(startText_b); endLabel->setText(endText); setTitle(page0, tText + " Wizard"); setTitle(page1, tText + " template selection"); setTitle(page2, tText + " personal settings"); setTitle(page4, tText + " X.509 v3 Extensions"); setTitle(page5, tText + " key usage setup"); setTitle(page6, tText + " Netscape extensions"); setTitle(page7, tText + " Wizard finished"); } 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(); #ifdef qt3 reqList->setCurrentText(reqname); #else for (int i=0; icount(); i++) { if (reqList->text(i) == reqname) { reqList->setCurrentItem(i); break; } } #endif } void NewX509::defineSigner(pki_x509 *defcert) { // suggested from: Andrey Brindeew if (defcert && defcert->canSign()) { QString name = defcert->getIntName(); #ifdef qt3 certList->setCurrentText(name); #else for (int i=0; icount();i++) { if (certList->text(i) == name) { certList->setCurrentItem(i); break; } } #endif foreignSignRB->setChecked(true); certList->setEnabled(true); } } int NewX509::lb2int(QListBox *lb) { int x=0; for (int i=0; lb->item(i); i++) { if (lb->isSelected(i)){ x |= 1<item(i); i++) { lb->setSelected(i, (1<xname); subAltName->setText(temp->subAltName); issAltName->setText(temp->issAltName); crlDist->setText(temp->crlDist); setAuthInfAcc_string(temp->authInfAcc); certPol->setText(temp->certPol); 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->setCurrentItem(temp->ca); bcCritical->setChecked(temp->bcCrit); kuCritical->setChecked(temp->keyUseCrit); ekuCritical->setChecked(temp->eKeyUseCrit); subKey->setChecked(temp->subKey); authKey->setChecked(temp->authKey); //subAltCp->setChecked(temp->subAltCp); //issAltCp->setChecked(temp->issAltCp); int2lb(keyUsage, temp->keyUse); int2lb(ekeyUsage, temp->eKeyUse); validNumber->setText(QString::number(temp->validN)); validRange->setCurrentItem(temp->validM); midnightCB->setChecked(temp->validMidn); if (temp->pathLen) { basicPath->setText(QString::number(temp->pathLen)); } notBefore->setNow(); applyTimeDiff(); } 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->certPol = certPol->text(); 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->currentItem(); temp->bcCrit = bcCritical->isChecked(); temp->keyUseCrit = kuCritical->isChecked(); temp->eKeyUseCrit = ekuCritical->isChecked(); temp->subKey = subKey->isChecked(); temp->authKey = authKey->isChecked(); // temp->subAltCp = subAltCp->isChecked(); // temp->issAltCp = issAltCp->isChecked(); temp->keyUse = lb2int(keyUsage); temp->eKeyUse = lb2int(ekeyUsage); temp->validN = validNumber->text().toInt(); temp->validM = validRange->currentItem(); temp->pathLen = basicPath->text().toInt(); temp->validMidn = midnightCB->isChecked(); } void NewX509::toggleFromRequest() { if (fromReqCB->isChecked()) { setAppropriate(page2, false); reqList->setEnabled(true); } else { setAppropriate(page2, true); reqList->setEnabled(false); } } void NewX509::keyChanged(const QString &keyname) { if ( keyname.right(5) == "(DSA)" ) hashAlgo->setDisabled(true); else hashAlgo->setDisabled(false); } void NewX509::dataChangeP2() { if (description->text() != "" && countryName->text().length() !=1 && (keyList->count() > 0 || !keyList->isEnabled())){ setNextEnabled(page2,true); } else { setNextEnabled(page2,false); } } void NewX509::showPage(QWidget *page) { if (page == page0) { signerChanged(); switchExtended(); toggleFromRequest(); } else if ( page == page2 ) { if (keyList->isEnabled() && keyList->count() == 0 ) { emit genKey(); } dataChangeP2(); } if (page == page7) { QString issn, subn; if (fromReqCB->isChecked()) { pki_x509req *req = getSelectedReq(); if (req) { subn = req->getSubject().oneLine(); } } else subn = getX509name().oneLine(); pki_x509 *issuer = getSelectedSigner(); if (issuer && foreignSignRB->isChecked()) issn = issuer->getSubject().oneLine(); else issn = subn; subn = "

Subject: " + subn; issn = "

Issuer: " + issn; if (!appropriate(page1)) issn = ""; v3Extensions->setText( subn + issn + "

" + createRequestText() ); } if (page == page4) { checkAuthKeyId(); } QWizard::showPage(page); if ( page == page2 ) { description->setFocus(); } else if (page == page4) { basicCA->setFocus(); } } void NewX509::signerChanged() { a1time snb, sna; pki_x509 *cert = getSelectedSigner(); 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) { if (!tempList->isEnabled()) return; #ifdef qt3 tempList->setCurrentText(tempname); #else for (int i=0; icount();i++) { if (tempList->text(i) == tempname) { tempList->setCurrentItem(i); break; } } #endif templateChanged(); } void NewX509::templateChanged(pki_temp *templ) { QString tempname = templ->getIntName(); templateChanged(tempname); } void NewX509::templateChanged() { pki_temp *temp = NULL; int item; if (!appropriate(page1)) return; if (!tempList->isEnabled()) return; if ((item = tempList->currentItem())<4) { temp = new pki_temp("temp",item); if (temp) { fromTemplate(temp); delete (temp); } return; } QString name = tempList->currentText(); if (name.isEmpty()) return; temp = (pki_temp *)MainWindow::temps->getByName(name); if (!temp) return; fromTemplate(temp); } void NewX509::switchExtended() { if ( !appropriate(page1) ) return; if (changeDefault->isChecked() || !templateBox->isEnabled()) { setAppropriate(page4, true); setAppropriate(page5, true); setAppropriate(page6, true); } else { setAppropriate(page4, false); setAppropriate(page5, false); setAppropriate(page6, false); } } void NewX509::checkAuthKeyId() { bool enabled = false; // for Templates: if ( !appropriate(page1) ) enabled = true ; if (foreignSignRB->isChecked()) { //if (getSelectedSigner()->hasSubAltName()) enabled = true; } else { // Self signed if (subKey->isChecked() && subKey->isEnabled()) enabled = true; } authKey->setEnabled(enabled); } void NewX509::newKeyDone(QString name) { keyList->insertItem(name,0); keyList->setCurrentItem(0); dataChangeP2(); } void NewX509::helpClicked() { QWhatsThis::enterWhatsThisMode(); } 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() { x509name x; for (int j = 0; jtext()); } QListViewItem *lvi = extDNlist->firstChild(); while (lvi != NULL) { int nid; nid = OBJ_ln2nid(lvi->text(0).latin1()); x.addEntryByNid(nid, lvi->text(1)); lvi = lvi->nextSibling(); } return x; } void NewX509::setX509name(const x509name &n) { int j; extDNlist->clear(); for ( j = 0; jsetText(""); } for ( int i=0; i< n.entryCount(); i++) { int nid = n.nid(i); QStringList sl = n.entryList(i); for ( j = 0; jtext().isEmpty()) { name_ptr[j]->setText(sl[2]); break; } } if (j == EXPLICIT_NAME_CNT) { new QListViewItem(extDNlist, sl[1], sl[2]); } } } void NewX509::addX509NameEntry() { new QListViewItem(extDNlist, extDNobj->currentText(), extDNname->text()); } void NewX509::delX509NameEntry() { extDNlist->removeItem(extDNlist->currentItem()); } const EVP_MD *NewX509::getHashAlgo() { const EVP_MD *ha[] = {EVP_md2(), EVP_md5(), EVP_sha1()}; return ha[hashAlgo->currentItem()]; } void NewX509::applyTimeDiff() { #define d_fac (60 * 60 * 24) int faktor[] = { 1, 30, 365 }; int N = validNumber->text().toInt(); int M = validRange->currentItem(); int midnight = midnightCB->isChecked()? 1:0; if (M>2||M<0) M=0; a1time a; time_t t; time(&t); int delta = faktor[M] * N ; t /= d_fac; if (delta + t > 24850){ QMessageBox::warning(this, XCA_TITLE, "Time difference too big\nYou must set it manually." ); return; } notBefore->setDate(a.now(), midnight); notAfter->setDate(a.now(delta * d_fac), midnight* (-1)); } void NewX509::editV3ext(QLineEdit *le, QString types, int n) { v3ext *dlg; pki_x509 *cert, *signcert; pki_x509req *req; // initially create cert cert = new pki_x509(); if (fromReqCB->isChecked()) { req = getSelectedReq(); cert->setSubject(req->getSubject()); } else { cert->setSubject(getX509name()); } // Step 2 - select Signing if (foreignSignRB->isChecked()) { signcert = getSelectedSigner(); } else { signcert = cert; } dlg = new v3ext(this, NULL, true); dlg->addInfo(le, QStringList::split(',', types ), n, signcert->getCert(), cert->getCert()); dlg->exec(); delete(dlg); delete(cert); } void NewX509::editSubAltName() { #if OPENSSL_VERSION_NUMBER >= 0x00908000L editV3ext(subAltName, "email,email:copy,RID,URI,DNS,IP,otherName", NID_subject_alt_name); #else editV3ext(subAltName, "email,email:copy,RID,URI,DNS,IP", NID_subject_alt_name); #endif } void NewX509::editIssAltName() { #if OPENSSL_VERSION_NUMBER >= 0x00908000L editV3ext(issAltName, "email,RID,URI,DNS,IP,issuer:copy,otherName", NID_issuer_alt_name); #else editV3ext(issAltName, "email,RID,URI,DNS,IP,issuer:copy", NID_issuer_alt_name); #endif } void NewX509::editCrlDist() { editV3ext(crlDist, "URI", NID_crl_distribution_points); } void NewX509::editAuthInfAcc() { editV3ext(authInfAcc, "email,RID,URI,DNS,IP", NID_info_access); }