• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • KDE Support
  • Sitemap
  • Contact Us
 

qca

qca_cert.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2003-2007  Justin Karneges <justin@affinix.com>
00003  * Copyright (C) 2004-2006  Brad Hards <bradh@frogmouth.net>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Lesser General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2.1 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public
00016  * License along with this library; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00018  * 02110-1301  USA
00019  *
00020  */
00021 
00022 #include "qca_cert.h"
00023 
00024 #include "qca_publickey.h"
00025 #include "qcaprovider.h"
00026 
00027 #include <QTextStream>
00028 #include <QFile>
00029 #include <QUrl>
00030 
00031 #include <stdlib.h>
00032 
00033 namespace QCA {
00034 
00035 Provider::Context *getContext(const QString &type, const QString &provider);
00036 Provider::Context *getContext(const QString &type, Provider *p);
00037 
00038 // from qca_publickey.cpp
00039 bool stringToFile(const QString &fileName, const QString &content);
00040 bool stringFromFile(const QString &fileName, QString *s);
00041 bool arrayToFile(const QString &fileName, const QByteArray &content);
00042 bool arrayFromFile(const QString &fileName, QByteArray *a);
00043 bool ask_passphrase(const QString &fname, void *ptr, SecureArray *answer);
00044 ProviderList allProviders();
00045 Provider *providerForName(const QString &name);
00046 bool use_asker_fallback(ConvertResult r);
00047 
00048 // last 3 arguments must be valid, and chain must be empty
00049 static bool get_pkcs12_der(const QByteArray &der, const QString &fileName, void *ptr, const SecureArray &passphrase, ConvertResult *result, const QString &provider, QString *name, CertificateChain *chain, PrivateKey *key)
00050 {
00051     QString _name;
00052     QList<CertContext*> list;
00053     PKeyContext *kc = 0;
00054 
00055     PKCS12Context *pix = static_cast<PKCS12Context *>(getContext("pkcs12", provider));
00056     ConvertResult r = pix->fromPKCS12(der, passphrase, &_name, &list, &kc);
00057 
00058     // error converting without passphrase?  maybe a passphrase is needed
00059     if(use_asker_fallback(r) && passphrase.isEmpty())
00060     {
00061         SecureArray pass;
00062         if(ask_passphrase(fileName, ptr, &pass))
00063             r = pix->fromPKCS12(der, pass, &_name, &list, &kc);
00064     }
00065     delete pix;
00066 
00067     if(result)
00068         *result = r;
00069 
00070     if(r == ConvertGood)
00071     {
00072         *name = _name;
00073         for(int n = 0; n < list.count(); ++n)
00074         {
00075             Certificate cert;
00076             cert.change(list[n]);
00077             chain->append(cert);
00078         }
00079         key->change(kc);
00080         return true;
00081     }
00082     return false;
00083 }
00084 
00085 static CertificateInfo orderedToMap(const CertificateInfoOrdered &info)
00086 {
00087     CertificateInfo out;
00088 
00089     // first, do all but EmailLegacy
00090     for(int n = 0; n < info.count(); ++n)
00091     {
00092         const CertificateInfoPair &i = info[n];
00093         if(i.type().known() != EmailLegacy)
00094             out.insert(i.type(), i.value());
00095     }
00096 
00097     // lastly, apply EmailLegacy
00098     for(int n = 0; n < info.count(); ++n)
00099     {
00100         const CertificateInfoPair &i = info[n];
00101         if(i.type().known() == EmailLegacy)
00102         {
00103             // de-dup
00104             QList<QString> emails = out.values(Email);
00105             if(!emails.contains(i.value()))
00106                 out.insert(Email, i.value());
00107         }
00108     }
00109 
00110     return out;
00111 }
00112 
00113 static void moveMapValues(CertificateInfo *from, CertificateInfoOrdered *to, const CertificateInfoType &type)
00114 {
00115     QList<QString> values = from->values(type);
00116     from->remove(type);
00117 
00118     // multimap values are stored in reverse.  we'll insert backwards in
00119     //   order to right them.
00120     for(int n = values.count() - 1; n >= 0; --n)
00121         to->append(CertificateInfoPair(type, values[n]));
00122 }
00123 
00124 static CertificateInfoOrdered mapToOrdered(const CertificateInfo &info)
00125 {
00126     CertificateInfo in = info;
00127     CertificateInfoOrdered out;
00128 
00129     // have a specific order for some types
00130     moveMapValues(&in, &out, CommonName);
00131     moveMapValues(&in, &out, Country);
00132     moveMapValues(&in, &out, Locality);
00133     moveMapValues(&in, &out, State);
00134     moveMapValues(&in, &out, Organization);
00135     moveMapValues(&in, &out, OrganizationalUnit);
00136     moveMapValues(&in, &out, Email);
00137     moveMapValues(&in, &out, URI);
00138     moveMapValues(&in, &out, DNS);
00139     moveMapValues(&in, &out, IPAddress);
00140     moveMapValues(&in, &out, XMPP);
00141 
00142     // get remaining types
00143     QList<CertificateInfoType> typesLeft = in.keys();
00144 
00145     // dedup
00146     QList<CertificateInfoType> types;
00147     for(int n = 0; n < typesLeft.count(); ++n)
00148     {
00149         if(!types.contains(typesLeft[n]))
00150             types += typesLeft[n];
00151     }
00152 
00153     // insert the rest of the types in the order we got them (map order)
00154     for(int n = 0; n < types.count(); ++n)
00155         moveMapValues(&in, &out, types[n]);
00156 
00157     Q_ASSERT(in.isEmpty());
00158 
00159     return out;
00160 }
00161 
00162 //----------------------------------------------------------------------------
00163 // Global
00164 //----------------------------------------------------------------------------
00165 static const char CommonName_id[]             = "2.5.4.3";
00166 static const char Email_id[]                  = "GeneralName.rfc822Name";
00167 static const char EmailLegacy_id[]            = "1.2.840.113549.1.9.1";
00168 static const char Organization_id[]           = "2.5.4.10";
00169 static const char OrganizationalUnit_id[]     = "2.5.4.11";
00170 static const char Locality_id[]               = "2.5.4.7";
00171 static const char IncorporationLocality_id[]  = "1.3.6.1.4.1.311.60.2.1.1";
00172 static const char State_id[]                  = "2.5.4.8";
00173 static const char IncorporationState_id[]     = "1.3.6.1.4.1.311.60.2.1.2";
00174 static const char Country_id[]                = "2.5.4.6";
00175 static const char IncorporationCountry_id[]   = "1.3.6.1.4.1.311.60.2.1.3";
00176 static const char URI_id[]                    = "GeneralName.uniformResourceIdentifier";
00177 static const char DNS_id[]                    = "GeneralName.dNSName";
00178 static const char IPAddress_id[]              = "GeneralName.iPAddress";
00179 static const char XMPP_id[]                   = "1.3.6.1.5.5.7.8.5";
00180 
00181 static const char DigitalSignature_id[]    = "KeyUsage.digitalSignature";
00182 static const char NonRepudiation_id[]      = "KeyUsage.nonRepudiation";
00183 static const char KeyEncipherment_id[]     = "KeyUsage.keyEncipherment";
00184 static const char DataEncipherment_id[]    = "KeyUsage.dataEncipherment";
00185 static const char KeyAgreement_id[]        = "KeyUsage.keyAgreement";
00186 static const char KeyCertificateSign_id[]  = "KeyUsage.keyCertSign";
00187 static const char CRLSign_id[]             = "KeyUsage.crlSign";
00188 static const char EncipherOnly_id[]        = "KeyUsage.encipherOnly";
00189 static const char DecipherOnly_id[]        = "KeyUsage.decipherOnly";
00190 static const char ServerAuth_id[]          = "1.3.6.1.5.5.7.3.1";
00191 static const char ClientAuth_id[]          = "1.3.6.1.5.5.7.3.2";
00192 static const char CodeSigning_id[]         = "1.3.6.1.5.5.7.3.3";
00193 static const char EmailProtection_id[]     = "1.3.6.1.5.5.7.3.4";
00194 static const char IPSecEndSystem_id[]      = "1.3.6.1.5.5.7.3.5";
00195 static const char IPSecTunnel_id[]         = "1.3.6.1.5.5.7.3.6";
00196 static const char IPSecUser_id[]           = "1.3.6.1.5.5.7.3.7";
00197 static const char TimeStamping_id[]        = "1.3.6.1.5.5.7.3.8";
00198 static const char OCSPSigning_id[]         = "1.3.6.1.5.5.7.3.9";
00199 
00200 static QString knownToId(CertificateInfoTypeKnown k)
00201 {
00202     const char *out = 0;
00203     switch(k)
00204     {
00205         case CommonName:            out = CommonName_id; break;
00206         case Email:                 out = Email_id; break;
00207         case EmailLegacy:           out = EmailLegacy_id; break;
00208         case Organization:          out = Organization_id; break;
00209         case OrganizationalUnit:    out = OrganizationalUnit_id; break;
00210         case Locality:              out = Locality_id; break;
00211         case IncorporationLocality: out = IncorporationLocality_id; break;
00212         case State:                 out = State_id; break;
00213         case IncorporationState:    out = IncorporationState_id; break;
00214         case Country:               out = Country_id; break;
00215         case IncorporationCountry:  out = IncorporationCountry_id; break;
00216         case URI:                   out = URI_id; break;
00217         case DNS:                   out = DNS_id; break;
00218         case IPAddress:             out = IPAddress_id; break;
00219         case XMPP:                  out = XMPP_id; break;
00220     }
00221     Q_ASSERT(out);
00222     if(!out)
00223         abort();
00224     return QString(out);
00225 }
00226 
00227 static int idToKnown(const QString &id)
00228 {
00229     if(id == CommonName_id)
00230         return CommonName;
00231     else if(id == Email_id)
00232         return Email;
00233     else if(id == EmailLegacy_id)
00234         return EmailLegacy;
00235     else if(id == Organization_id)
00236         return Organization;
00237     else if(id == OrganizationalUnit_id)
00238         return OrganizationalUnit;
00239     else if(id == Locality_id)
00240         return Locality;
00241     else if(id == IncorporationLocality_id)
00242         return IncorporationLocality;
00243     else if(id == State_id)
00244         return State;
00245     else if(id == IncorporationState_id)
00246         return IncorporationState;
00247     else if(id == Country_id)
00248         return Country;
00249     else if(id == IncorporationCountry_id)
00250         return IncorporationCountry;
00251     else if(id == URI_id)
00252         return URI;
00253     else if(id == DNS_id)
00254         return DNS;
00255     else if(id == IPAddress_id)
00256         return IPAddress;
00257     else if(id == XMPP_id)
00258         return XMPP;
00259     else
00260         return -1;
00261 }
00262 
00263 static CertificateInfoType::Section knownToSection(CertificateInfoTypeKnown k)
00264 {
00265     switch(k)
00266     {
00267         case CommonName:
00268         case EmailLegacy:
00269         case Organization:
00270         case OrganizationalUnit:
00271         case Locality:
00272         case IncorporationLocality:
00273         case State:
00274         case IncorporationState:
00275         case Country:
00276         case IncorporationCountry:
00277             return CertificateInfoType::DN;
00278         default:
00279             break;
00280     }
00281     return CertificateInfoType::AlternativeName;
00282 }
00283 
00284 static const char *knownToShortName(CertificateInfoTypeKnown k)
00285 {
00286     switch(k)
00287     {
00288         case CommonName:         return "CN";
00289         case Locality:           return "L";
00290         case State:              return "ST";
00291         case Organization:       return "O";
00292         case OrganizationalUnit: return "OU";
00293         case Country:            return "C";
00294         case EmailLegacy:        return "emailAddress";
00295         default:                                      break;
00296     }
00297     return 0;
00298 }
00299 
00300 static QString constraintKnownToId(ConstraintTypeKnown k)
00301 {
00302     const char *out = 0;
00303     switch(k)
00304     {
00305         case DigitalSignature:   out = DigitalSignature_id; break;
00306         case NonRepudiation:     out = NonRepudiation_id; break;
00307         case KeyEncipherment:    out = KeyEncipherment_id; break;
00308         case DataEncipherment:   out = DataEncipherment_id; break;
00309         case KeyAgreement:       out = KeyAgreement_id; break;
00310         case KeyCertificateSign: out = KeyCertificateSign_id; break;
00311         case CRLSign:            out = CRLSign_id; break;
00312         case EncipherOnly:       out = EncipherOnly_id; break;
00313         case DecipherOnly:       out = DecipherOnly_id; break;
00314         case ServerAuth:         out = ServerAuth_id; break;
00315         case ClientAuth:         out = ClientAuth_id; break;
00316         case CodeSigning:        out = CodeSigning_id; break;
00317         case EmailProtection:    out = EmailProtection_id; break;
00318         case IPSecEndSystem:     out = IPSecEndSystem_id; break;
00319         case IPSecTunnel:        out = IPSecTunnel_id; break;
00320         case IPSecUser:          out = IPSecUser_id; break;
00321         case TimeStamping:       out = TimeStamping_id; break;
00322         case OCSPSigning:        out = OCSPSigning_id; break;
00323     }
00324     Q_ASSERT(out);
00325     if(!out)
00326         abort();
00327     return QString(out);
00328 }
00329 
00330 static int constraintIdToKnown(const QString &id)
00331 {
00332     if(id == DigitalSignature_id)
00333         return DigitalSignature;
00334     else if(id == NonRepudiation_id)
00335         return NonRepudiation;
00336     else if(id == KeyEncipherment_id)
00337         return KeyEncipherment;
00338     else if(id == DataEncipherment_id)
00339         return DataEncipherment;
00340     else if(id == KeyAgreement_id)
00341         return KeyAgreement;
00342     else if(id == KeyCertificateSign_id)
00343         return KeyCertificateSign;
00344     else if(id == CRLSign_id)
00345         return CRLSign;
00346     else if(id == EncipherOnly_id)
00347         return EncipherOnly;
00348     else if(id == DecipherOnly_id)
00349         return DecipherOnly;
00350     else if(id == ServerAuth_id)
00351         return ServerAuth;
00352     else if(id == ClientAuth_id)
00353         return ClientAuth;
00354     else if(id == CodeSigning_id)
00355         return CodeSigning;
00356     else if(id == EmailProtection_id)
00357         return EmailProtection;
00358     else if(id == IPSecEndSystem_id)
00359         return IPSecEndSystem;
00360     else if(id == IPSecTunnel_id)
00361         return IPSecTunnel;
00362     else if(id == IPSecUser_id)
00363         return IPSecUser;
00364     else if(id == TimeStamping_id)
00365         return TimeStamping;
00366     else if(id == OCSPSigning_id)
00367         return OCSPSigning;
00368     else
00369         return -1;
00370 }
00371 
00372 static ConstraintType::Section constraintKnownToSection(ConstraintTypeKnown k)
00373 {
00374     switch(k)
00375     {
00376         case DigitalSignature:
00377         case NonRepudiation:
00378         case KeyEncipherment:
00379         case DataEncipherment:
00380         case KeyAgreement:
00381         case KeyCertificateSign:
00382         case CRLSign:
00383         case EncipherOnly:
00384         case DecipherOnly:
00385             return ConstraintType::KeyUsage;
00386         default:
00387             break;
00388     }
00389     return ConstraintType::ExtendedKeyUsage;
00390 }
00391 
00392 static QString dnLabel(const CertificateInfoType &type)
00393 {
00394     const char *str = knownToShortName(type.known());
00395     if(str)
00396         return str;
00397 
00398     QString id = type.id();
00399     // is it an oid?
00400     if(id[0].isDigit())
00401         return QString("OID.") + id;
00402 
00403     return QString("qca.") + id;
00404 }
00405 
00406 QString orderedToDNString(const CertificateInfoOrdered &in)
00407 {
00408     QStringList parts;
00409     foreach(const CertificateInfoPair &i, in)
00410     {
00411         if(i.type().section() != CertificateInfoType::DN)
00412             continue;
00413 
00414         QString name = dnLabel(i.type());
00415         parts += name + '=' + i.value();
00416     }
00417     return parts.join(", ");
00418 }
00419 
00420 CertificateInfoOrdered orderedDNOnly(const CertificateInfoOrdered &in)
00421 {
00422     CertificateInfoOrdered out;
00423     for(int n = 0; n < in.count(); ++n)
00424     {
00425         if(in[n].type().section() == CertificateInfoType::DN)
00426             out += in[n];
00427     }
00428     return out;
00429 }
00430 
00431 static QString baseCertName(const CertificateInfo &info)
00432 {
00433     QString str = info.value(CommonName);
00434     if(str.isEmpty())
00435     {
00436         str = info.value(Organization);
00437         if(str.isEmpty())
00438             str = "Unnamed";
00439     }
00440     return str;
00441 }
00442 
00443 static QList<int> findSameName(const QString &name, const QStringList &list)
00444 {
00445     QList<int> out;
00446     for(int n = 0; n < list.count(); ++n)
00447     {
00448         if(list[n] == name)
00449             out += n;
00450     }
00451     return out;
00452 }
00453 
00454 static QString uniqueSubjectValue(const CertificateInfoType &type, const QList<int> items, const QList<Certificate> &certs, int i)
00455 {
00456     QStringList vals = certs[items[i]].subjectInfo().values(type);
00457     if(!vals.isEmpty())
00458     {
00459         foreach(int n, items)
00460         {
00461             if(n == items[i])
00462                 continue;
00463 
00464             QStringList other_vals = certs[n].subjectInfo().values(type);
00465             for(int k = 0; k < vals.count(); ++k)
00466             {
00467                 if(other_vals.contains(vals[k]))
00468                 {
00469                     vals.removeAt(k);
00470                     break;
00471                 }
00472             }
00473 
00474             if(vals.isEmpty())
00475                 break;
00476         }
00477 
00478         if(!vals.isEmpty())
00479             return vals[0];
00480     }
00481 
00482     return QString();
00483 }
00484 
00485 static QString uniqueIssuerName(const QList<int> items, const QList<Certificate> &certs, int i)
00486 {
00487     QString val = baseCertName(certs[items[i]].issuerInfo());
00488 
00489     bool found = false;
00490     foreach(int n, items)
00491     {
00492         if(n == items[i])
00493             continue;
00494 
00495         QString other_val = baseCertName(certs[n].issuerInfo());
00496         if(other_val == val)
00497         {
00498             found = true;
00499             break;
00500         }
00501     }
00502 
00503     if(!found)
00504         return val;
00505 
00506     return QString();
00507 }
00508 
00509 static const char *constraintToString(const ConstraintType &type)
00510 {
00511     switch(type.known())
00512     {
00513         case DigitalSignature:   return "DigitalSignature";
00514         case NonRepudiation:     return "NonRepudiation";
00515         case KeyEncipherment:    return "KeyEncipherment";
00516         case DataEncipherment:   return "DataEncipherment";
00517         case KeyAgreement:       return "KeyAgreement";
00518         case KeyCertificateSign: return "KeyCertificateSign";
00519         case CRLSign:            return "CRLSign";
00520         case EncipherOnly:       return "EncipherOnly";
00521         case DecipherOnly:       return "DecipherOnly";
00522         case ServerAuth:         return "ServerAuth";
00523         case ClientAuth:         return "ClientAuth";
00524         case CodeSigning:        return "CodeSigning";
00525         case EmailProtection:    return "EmailProtection";
00526         case IPSecEndSystem:     return "IPSecEndSystem";
00527         case IPSecTunnel:        return "IPSecTunnel";
00528         case IPSecUser:          return "IPSecUser";
00529         case TimeStamping:       return "TimeStamping";
00530         case OCSPSigning:        return "OCSPSigning";
00531     }
00532     return 0;
00533 }
00534 
00535 static QString uniqueConstraintValue(const ConstraintType &type, const QList<int> items, const QList<Certificate> &certs, int i)
00536 {
00537     ConstraintType val = type;
00538     if(certs[items[i]].constraints().contains(type))
00539     {
00540         bool found = false;
00541         foreach(int n, items)
00542         {
00543             if(n == items[i])
00544                 continue;
00545 
00546             Constraints other_vals = certs[n].constraints();
00547             if(other_vals.contains(val))
00548             {
00549                 found = true;
00550                 break;
00551             }
00552         }
00553 
00554         if(!found)
00555             return QString(constraintToString(val));
00556     }
00557 
00558     return QString();
00559 }
00560 
00561 static QString makeUniqueName(const QList<int> &items, const QStringList &list, const QList<Certificate> &certs, int i)
00562 {
00563     QString str, name;
00564 
00565     // different organization?
00566     str = uniqueSubjectValue(Organization, items, certs, i);
00567     if(!str.isEmpty())
00568     {
00569         name = list[items[i]] + QString(" of ") + str;
00570         goto end;
00571     }
00572 
00573     // different organizational unit?
00574     str = uniqueSubjectValue(OrganizationalUnit, items, certs, i);
00575     if(!str.isEmpty())
00576     {
00577         name = list[items[i]] + QString(" of ") + str;
00578         goto end;
00579     }
00580 
00581     // different email address?
00582     str = uniqueSubjectValue(Email, items, certs, i);
00583     if(!str.isEmpty())
00584     {
00585         name = list[items[i]] + QString(" <") + str + '>';
00586         goto end;
00587     }
00588 
00589     // different xmpp addresses?
00590     str = uniqueSubjectValue(XMPP, items, certs, i);
00591     if(!str.isEmpty())
00592     {
00593         name = list[items[i]] + QString(" <xmpp:") + str + '>';
00594         goto end;
00595     }
00596 
00597     // different issuers?
00598     str = uniqueIssuerName(items, certs, i);
00599     if(!str.isEmpty())
00600     {
00601         name = list[items[i]] + QString(" by ") + str;
00602         goto end;
00603     }
00604 
00605     // different usages?
00606 
00607     // DigitalSignature
00608     str = uniqueConstraintValue(DigitalSignature, items, certs, i);
00609     if(!str.isEmpty())
00610     {
00611         name = list[items[i]] + QString(" for ") + str;
00612         goto end;
00613     }
00614 
00615     // ClientAuth
00616     str = uniqueConstraintValue(ClientAuth, items, certs, i);
00617     if(!str.isEmpty())
00618     {
00619         name = list[items[i]] + QString(" for ") + str;
00620         goto end;
00621     }
00622 
00623     // EmailProtection
00624     str = uniqueConstraintValue(EmailProtection, items, certs, i);
00625     if(!str.isEmpty())
00626     {
00627         name = list[items[i]] + QString(" for ") + str;
00628         goto end;
00629     }
00630 
00631     // DataEncipherment
00632     str = uniqueConstraintValue(DataEncipherment, items, certs, i);
00633     if(!str.isEmpty())
00634     {
00635         name = list[items[i]] + QString(" for ") + str;
00636         goto end;
00637     }
00638 
00639     // EncipherOnly
00640     str = uniqueConstraintValue(EncipherOnly, items, certs, i);
00641     if(!str.isEmpty())
00642     {
00643         name = list[items[i]] + QString(" for ") + str;
00644         goto end;
00645     }
00646 
00647     // DecipherOnly
00648     str = uniqueConstraintValue(DecipherOnly, items, certs, i);
00649     if(!str.isEmpty())
00650     {
00651         name = list[items[i]] + QString(" for ") + str;
00652         goto end;
00653     }
00654 
00655     // if there's nothing easily unique, then do a DN string
00656     name = certs[items[i]].subjectInfoOrdered().toString();
00657 
00658 end:
00659     return name;
00660 }
00661 
00662 QStringList makeFriendlyNames(const QList<Certificate> &list)
00663 {
00664     QStringList names;
00665 
00666     // give a base name to all certs first
00667     foreach(const Certificate &cert, list)
00668         names += baseCertName(cert.subjectInfo());
00669 
00670     // come up with a collision list
00671     QList< QList<int> > itemCollisions;
00672     foreach(const QString &name, names)
00673     {
00674         // anyone else using this name?
00675         QList<int> items = findSameName(name, names);
00676         if(items.count() > 1)
00677         {
00678             // don't save duplicate collisions
00679             bool haveAlready = false;
00680             foreach(const QList<int> &other, itemCollisions)
00681             {
00682                 foreach(int n, items)
00683                 {
00684                     if(other.contains(n))
00685                     {
00686                         haveAlready = true;
00687                         break;
00688                     }
00689                 }
00690 
00691                 if(haveAlready)
00692                     break;
00693             }
00694 
00695             if(haveAlready)
00696                 continue;
00697 
00698             itemCollisions += items;
00699         }
00700     }
00701 
00702     // resolve collisions by providing extra details
00703     foreach(const QList<int> &items, itemCollisions)
00704     {
00705         //printf("%d items are using [%s]\n", items.count(), qPrintable(names[items[0]]));
00706 
00707         for(int n = 0; n < items.count(); ++n)
00708         {
00709             names[items[n]] = makeUniqueName(items, names, list, n);
00710             //printf("  %d: reassigning: [%s]\n", items[n], qPrintable(names[items[n]]));
00711         }
00712     }
00713 
00714     return names;
00715 }
00716 
00717 //----------------------------------------------------------------------------
00718 // CertificateInfoType
00719 //----------------------------------------------------------------------------
00720 class CertificateInfoType::Private : public QSharedData
00721 {
00722 public:
00723     CertificateInfoType::Section section;
00724     int known;
00725     QString id;
00726 
00727     Private() :
00728         section(CertificateInfoType::DN),
00729         known(-1)
00730     {
00731     }
00732 };
00733 
00734 CertificateInfoType::CertificateInfoType()
00735 :d(new Private)
00736 {
00737 }
00738 
00739 CertificateInfoType::CertificateInfoType(CertificateInfoTypeKnown known)
00740 :d(new Private)
00741 {
00742     d->section = knownToSection(known);
00743     d->known = known;
00744     d->id = knownToId(known); // always valid
00745 }
00746 
00747 CertificateInfoType::CertificateInfoType(const QString &id, Section section)
00748 :d(new Private)
00749 {
00750     d->section = section;
00751     d->known = idToKnown(id); // can be -1 for unknown
00752     d->id = id;
00753 }
00754 
00755 CertificateInfoType::CertificateInfoType(const CertificateInfoType &from)
00756 :d(from.d)
00757 {
00758 }
00759 
00760 CertificateInfoType::~CertificateInfoType()
00761 {
00762 }
00763 
00764 CertificateInfoType & CertificateInfoType::operator=(const CertificateInfoType &from)
00765 {
00766     d = from.d;
00767     return *this;
00768 }
00769 
00770 CertificateInfoType::Section CertificateInfoType::section() const
00771 {
00772     return d->section;
00773 }
00774 
00775 CertificateInfoTypeKnown CertificateInfoType::known() const
00776 {
00777     return (CertificateInfoTypeKnown)d->known;
00778 }
00779 
00780 QString CertificateInfoType::id() const
00781 {
00782     return d->id;
00783 }
00784 
00785 bool CertificateInfoType::operator<(const CertificateInfoType &other) const
00786 {
00787     // sort by knowns (in enum order), then by ids (in string order)
00788     if(d->known != -1)
00789     {
00790         if(other.d->known == -1)
00791             return true;
00792         else if(d->known < other.d->known)
00793             return true;
00794         else
00795             return false;
00796     }
00797     else
00798     {
00799         if(other.d->known != -1)
00800             return false;
00801         else if(d->id < other.d->id)
00802             return true;
00803         else
00804             return false;
00805     }
00806 }
00807 
00808 bool CertificateInfoType::operator==(const CertificateInfoType &other) const
00809 {
00810     // are both known types?
00811     if(d->known != -1 && other.d->known != -1)
00812     {
00813         // if so, compare the ints
00814         if(d->known != other.d->known)
00815             return false;
00816     }
00817     else
00818     {
00819         // otherwise, compare the string ids
00820         if(d->id != other.d->id)
00821             return false;
00822     }
00823 
00824     if(d->section != other.d->section)
00825         return false;
00826 
00827     return true;
00828 }
00829 
00830 //----------------------------------------------------------------------------
00831 // CertificateInfoPair
00832 //----------------------------------------------------------------------------
00833 class CertificateInfoPair::Private : public QSharedData
00834 {
00835 public:
00836     CertificateInfoType type;
00837     QString value;
00838 };
00839 
00840 CertificateInfoPair::CertificateInfoPair()
00841 :d(new Private)
00842 {
00843 }
00844 
00845 CertificateInfoPair::CertificateInfoPair(const CertificateInfoType &type, const QString &value)
00846 :d(new Private)
00847 {
00848     d->type = type;
00849     d->value = value;
00850 }
00851 
00852 CertificateInfoPair::CertificateInfoPair(const CertificateInfoPair &from)
00853 :d(from.d)
00854 {
00855 }
00856 
00857 CertificateInfoPair::~CertificateInfoPair()
00858 {
00859 }
00860 
00861 CertificateInfoPair & CertificateInfoPair::operator=(const CertificateInfoPair &from)
00862 {
00863     d = from.d;
00864     return *this;
00865 }
00866 
00867 CertificateInfoType CertificateInfoPair::type() const
00868 {
00869     return d->type;
00870 }
00871 
00872 QString CertificateInfoPair::value() const
00873 {
00874     return d->value;
00875 }
00876 
00877 bool CertificateInfoPair::operator==(const CertificateInfoPair &other) const
00878 {
00879     if(d->type == other.d->type && d->value == other.d->value)
00880         return true;
00881     return false;
00882 }
00883 
00884 //----------------------------------------------------------------------------
00885 // ConstraintType
00886 //----------------------------------------------------------------------------
00887 class ConstraintType::Private : public QSharedData
00888 {
00889 public:
00890     ConstraintType::Section section;
00891     int known;
00892     QString id;
00893 
00894     Private() :
00895         section(ConstraintType::KeyUsage),
00896         known(-1)
00897     {
00898     }
00899 };
00900 
00901 ConstraintType::ConstraintType()
00902 :d(new Private)
00903 {
00904 }
00905 
00906 ConstraintType::ConstraintType(ConstraintTypeKnown known)
00907 :d(new Private)
00908 {
00909     d->section = constraintKnownToSection(known);
00910     d->known = known;
00911     d->id = constraintKnownToId(known); // always valid
00912 }
00913 
00914 ConstraintType::ConstraintType(const QString &id, Section section)
00915 :d(new Private)
00916 {
00917     d->section = section;
00918     d->known = constraintIdToKnown(id); // can be -1 for unknown
00919     d->id = id;
00920 }
00921 
00922 ConstraintType::ConstraintType(const ConstraintType &from)
00923 :d(from.d)
00924 {
00925 }
00926 
00927 ConstraintType::~ConstraintType()
00928 {
00929 }
00930 
00931 ConstraintType & ConstraintType::operator=(const ConstraintType &from)
00932 {
00933     d = from.d;
00934     return *this;
00935 }
00936 
00937 ConstraintType::Section ConstraintType::section() const
00938 {
00939     return d->section;
00940 }
00941 
00942 ConstraintTypeKnown ConstraintType::known() const
00943 {
00944     return (ConstraintTypeKnown)d->known;
00945 }
00946 
00947 QString ConstraintType::id() const
00948 {
00949     return d->id;
00950 }
00951 
00952 bool ConstraintType::operator<(const ConstraintType &other) const
00953 {
00954     // sort by knowns (in enum order), then by ids (in string order)
00955     if(d->known != -1)
00956     {
00957         if(other.d->known == -1)
00958             return true;
00959         else if(d->known < other.d->known)
00960             return true;
00961         else
00962             return false;
00963     }
00964     else
00965     {
00966         if(other.d->known != -1)
00967             return false;
00968         else if(d->id < other.d->id)
00969             return true;
00970         else
00971             return false;
00972     }
00973 }
00974 
00975 bool ConstraintType::operator==(const ConstraintType &other) const
00976 {
00977     // are both known types?
00978     if(d->known != -1 && other.d->known != -1)
00979     {
00980         // if so, compare the ints
00981         if(d->known != other.d->known)
00982             return false;
00983     }
00984     else
00985     {
00986         // otherwise, compare the string ids
00987         if(d->id != other.d->id)
00988             return false;
00989     }
00990 
00991     if(d->section != other.d->section)
00992         return false;
00993 
00994     return true;
00995 }
00996 
00997 //----------------------------------------------------------------------------
00998 // CertificateOptions
00999 //----------------------------------------------------------------------------
01000 class CertificateOptions::Private
01001 {
01002 public:
01003     CertificateRequestFormat format;
01004 
01005     QString challenge;
01006     CertificateInfoOrdered info;
01007     CertificateInfo infoMap;
01008     Constraints constraints;
01009     QStringList policies;
01010     QStringList crlLocations, issuerLocations, ocspLocations;
01011     bool isCA;
01012     int pathLimit;
01013     BigInteger serial;
01014     QDateTime start, end;
01015 
01016     Private() : isCA(false), pathLimit(0)
01017     {
01018     }
01019 };
01020 
01021 CertificateOptions::CertificateOptions(CertificateRequestFormat f)
01022 {
01023     d = new Private;
01024     d->format = f;
01025 }
01026 
01027 CertificateOptions::CertificateOptions(const CertificateOptions &from)
01028 {
01029     d = new Private(*from.d);
01030 }
01031 
01032 CertificateOptions::~CertificateOptions()
01033 {
01034     delete d;
01035 }
01036 
01037 CertificateOptions & CertificateOptions::operator=(const CertificateOptions &from)
01038 {
01039     *d = *from.d;
01040     return *this;
01041 }
01042 
01043 CertificateRequestFormat CertificateOptions::format() const
01044 {
01045     return d->format;
01046 }
01047 
01048 void CertificateOptions::setFormat(CertificateRequestFormat f)
01049 {
01050     d->format = f;
01051 }
01052 
01053 bool CertificateOptions::isValid() const
01054 {
01055     // logic from Botan
01056     if(d->infoMap.value(CommonName).isEmpty() || d->infoMap.value(Country).isEmpty())
01057         return false;
01058     if(d->infoMap.value(Country).length() != 2)
01059         return false;
01060     if(d->start >= d->end)
01061         return false;
01062     return true;
01063 }
01064 
01065 QString CertificateOptions::challenge() const
01066 {
01067     return d->challenge;
01068 }
01069 
01070 CertificateInfo CertificateOptions::info() const
01071 {
01072     return d->infoMap;
01073 }
01074 
01075 CertificateInfoOrdered CertificateOptions::infoOrdered() const
01076 {
01077     return d->info;
01078 }
01079 
01080 Constraints CertificateOptions::constraints() const
01081 {
01082     return d->constraints;
01083 }
01084 
01085 QStringList CertificateOptions::policies() const
01086 {
01087     return d->policies;
01088 }
01089 
01090 QStringList CertificateOptions::crlLocations() const
01091 {
01092     return d->crlLocations;
01093 }
01094 
01095 QStringList CertificateOptions::issuerLocations() const
01096 {
01097     return d->issuerLocations;
01098 }
01099 
01100 QStringList CertificateOptions::ocspLocations() const
01101 {
01102     return d->ocspLocations;
01103 }
01104 
01105 bool CertificateOptions::isCA() const
01106 {
01107     return d->isCA;
01108 }
01109 
01110 int CertificateOptions::pathLimit() const
01111 {
01112     return d->pathLimit;
01113 }
01114 
01115 BigInteger CertificateOptions::serialNumber() const
01116 {
01117     return d->serial;
01118 }
01119 
01120 QDateTime CertificateOptions::notValidBefore() const
01121 {
01122     return d->start;
01123 }
01124 
01125 QDateTime CertificateOptions::notValidAfter() const
01126 {
01127     return d->end;
01128 }
01129 
01130 void CertificateOptions::setChallenge(const QString &s)
01131 {
01132     d->challenge = s;
01133 }
01134 
01135 void CertificateOptions::setInfo(const CertificateInfo &info)
01136 {
01137     d->info = mapToOrdered(info);
01138     d->infoMap = info;
01139 }
01140 
01141 void CertificateOptions::setInfoOrdered(const CertificateInfoOrdered &info)
01142 {
01143     d->info = info;
01144     d->infoMap = orderedToMap(info);
01145 }
01146 
01147 void CertificateOptions::setConstraints(const Constraints &constraints)
01148 {
01149     d->constraints = constraints;
01150 }
01151 
01152 void CertificateOptions::setPolicies(const QStringList &policies)
01153 {
01154     d->policies = policies;
01155 }
01156 
01157 void CertificateOptions::setCRLLocations(const QStringList &locations)
01158 {
01159     d->crlLocations = locations;
01160 }
01161 
01162 void CertificateOptions::setIssuerLocations(const QStringList &locations)
01163 {
01164     d->issuerLocations = locations;
01165 }
01166 
01167 void CertificateOptions::setOCSPLocations(const QStringList &locations)
01168 {
01169     d->ocspLocations = locations;
01170 }
01171 
01172 void CertificateOptions::setAsCA(int pathLimit)
01173 {
01174     d->isCA = true;
01175     d->pathLimit = pathLimit;
01176 }
01177 
01178 void CertificateOptions::setAsUser()
01179 {
01180     d->isCA = false;
01181     d->pathLimit = 0;
01182 }
01183 
01184 void CertificateOptions::setSerialNumber(const BigInteger &i)
01185 {
01186     d->serial = i;
01187 }
01188 
01189 void CertificateOptions::setValidityPeriod(const QDateTime &start, const QDateTime &end)
01190 {
01191     d->start = start;
01192     d->end = end;
01193 }
01194 
01195 //----------------------------------------------------------------------------
01196 // Certificate
01197 //----------------------------------------------------------------------------
01198 // ip address string to binary (msb), adapted from jdns (adapted from qt)
01199 // return: size 4 = ipv4, size 16 = ipv6, size 0 = error
01200 static QByteArray ipaddr_str2bin(const QString &str)
01201 {
01202     // ipv6
01203     if(str.contains(':'))
01204     {
01205         QStringList parts = str.split(':', QString::KeepEmptyParts);
01206         if(parts.count() < 3 || parts.count() > 8)
01207             return QByteArray();
01208 
01209         QByteArray ipv6(16, 0);
01210         int at = 16;
01211         int fill = 9 - parts.count();
01212         for(int n = parts.count() - 1; n >= 0; --n)
01213         {
01214             if(at <= 0)
01215                 return QByteArray();
01216 
01217             if(parts[n].isEmpty())
01218             {
01219                 if(n == parts.count() - 1)
01220                 {
01221                     if(!parts[n - 1].isEmpty())
01222                         return QByteArray();
01223                     ipv6[--at] = 0;
01224                     ipv6[--at] = 0;
01225                 }
01226                 else if(n == 0)
01227                 {
01228                     if(!parts[n + 1].isEmpty())
01229                         return QByteArray();
01230                     ipv6[--at] = 0;
01231                     ipv6[--at] = 0;
01232                 }
01233                 else
01234                 {
01235                     for(int i = 0; i < fill; ++i)
01236                     {
01237                         if(at <= 0)
01238                             return QByteArray();
01239                         ipv6[--at] = 0;
01240                         ipv6[--at] = 0;
01241                     }
01242                 }
01243             }
01244             else
01245             {
01246                 if(parts[n].indexOf('.') == -1)
01247                 {
01248                     bool ok;
01249                     int x = parts[n].toInt(&ok, 16);
01250                     if(!ok || x < 0 || x > 0xffff)
01251                         return QByteArray();
01252                     ipv6[--at] = x & 0xff;
01253                     ipv6[--at] = (x >> 8) & 0xff;
01254                 }
01255                 else
01256                 {
01257                     if(n != parts.count() - 1)
01258                         return QByteArray();
01259 
01260                     QByteArray buf = ipaddr_str2bin(parts[n]);
01261                     if(buf.isEmpty())
01262                         return QByteArray();
01263 
01264                     ipv6[--at] = buf[3];
01265                     ipv6[--at] = buf[2];
01266                     ipv6[--at] = buf[1];
01267                     ipv6[--at] = buf[0];
01268                     --fill;
01269                 }
01270             }
01271         }
01272 
01273         return ipv6;
01274     }
01275     else if(str.contains('.'))
01276     {
01277         QStringList parts = str.split('.', QString::KeepEmptyParts);
01278         if(parts.count() != 4)
01279             return QByteArray();
01280 
01281         QByteArray out(4, 0);
01282         for(int n = 0; n < 4; ++n)
01283         {
01284             bool ok;
01285             int x = parts[n].toInt(&ok);
01286             if(!ok || x < 0 || x > 0xff)
01287                 return QByteArray();
01288             out[n] = (unsigned char)x;
01289         }
01290         return out;
01291     }
01292     else
01293         return QByteArray();
01294 }
01295 
01296 // acedomain must be all lowercase, with no trailing dot or wildcards
01297 static bool cert_match_domain(const QString &certname, const QString &acedomain)
01298 {
01299     // KSSL strips start/end whitespace, even though such whitespace is
01300     //   probably not legal anyway. (compat)
01301     QString name = certname.trimmed();
01302 
01303     // KSSL strips trailing dot, even though the dot is probably not
01304     //   legal anyway. (compat)
01305     if(name.length() > 0 && name[name.length()-1] == '.')
01306         name.truncate(name.length()-1);
01307 
01308     // after our compatibility modifications, make sure the name isn't
01309     //   empty.
01310     if(name.isEmpty())
01311         return false;
01312 
01313     // lowercase, for later performing case insensitive matching
01314     name = name.toLower();
01315 
01316     // ensure the cert field contains valid characters only
01317     if(QRegExp("[^a-z0-9\\.\\*\\-]").indexIn(name) >= 0)
01318         return false;
01319 
01320     // hack into parts, and require at least 1 part
01321     QStringList parts_name = name.split('.', QString::KeepEmptyParts);
01322     if(parts_name.isEmpty())
01323         return false;
01324 
01325     // KSSL checks to make sure the last two parts don't contain
01326     //   wildcards.  I don't know where it is written that this
01327     //   should be done, but for compat sake we'll do it.
01328     if(parts_name[parts_name.count()-1].contains('*'))
01329         return false;
01330     if(parts_name.count() >= 2 && parts_name[parts_name.count()-2].contains('*'))
01331         return false;
01332 
01333     QStringList parts_compare = acedomain.split('.', QString::KeepEmptyParts);
01334     if(parts_compare.isEmpty())
01335         return false;
01336 
01337     // don't allow empty parts
01338     foreach(const QString &s, parts_name)
01339     {
01340         if(s.isEmpty())
01341             return false;
01342     }
01343     foreach(const QString &s, parts_compare)
01344     {
01345         if(s.isEmpty())
01346             return false;
01347     }
01348 
01349     // RFC2818: "Names may contain the wildcard character * which is
01350     //   considered to match any single domain name component or
01351     //   component fragment. E.g., *.a.com matches foo.a.com but not
01352     //   bar.foo.a.com. f*.com matches foo.com but not bar.com."
01353     //
01354     // This means that for the domain to match it must have the
01355     //   same number of components, wildcards or not.  If there are
01356     //   wildcards, their scope must only be within the component
01357     //   they reside in.
01358     //
01359     // First, make sure the number of parts is equal.
01360     if(parts_name.count() != parts_compare.count())
01361         return false;
01362 
01363     // Now compare each part
01364     for(int n = 0; n < parts_name.count(); ++n)
01365     {
01366         const QString &p1 = parts_name[n];
01367         const QString &p2 = parts_compare[n];
01368 
01369         if(!QRegExp(p1, Qt::CaseSensitive, QRegExp::Wildcard).exactMatch(p2))
01370             return false;
01371     }
01372 
01373     return true;
01374 }
01375 
01376 // ipaddress must be an ipv4 or ipv6 address in binary format
01377 static bool cert_match_ipaddress(const QString &certname, const QByteArray &ipaddress)
01378 {
01379     // KSSL strips start/end whitespace, even though such whitespace is
01380     //   probably not legal anyway. (compat)
01381     QString name = certname.trimmed();
01382 
01383     // KSSL accepts IPv6 in brackets, which is usually done for URIs, but
01384     //   IMO sounds very strange for a certificate.  We'll follow this
01385     //   behavior anyway. (compat)
01386     if(name.length() >= 2 && name[0] == '[' && name[name.length()-1] == ']')
01387         name = name.mid(1, name.length() - 2); // chop off brackets
01388 
01389     // after our compatibility modifications, make sure the name isn't
01390     //   empty.
01391     if(name.isEmpty())
01392         return false;
01393 
01394     // convert to binary form
01395     QByteArray addr = ipaddr_str2bin(name);
01396     if(addr.isEmpty())
01397         return false;
01398 
01399     // not the same?
01400     if(addr != ipaddress)
01401         return false;
01402 
01403     return true;
01404 }
01405 
01406 class Certificate::Private : public QSharedData
01407 {
01408 public:
01409     CertificateInfo subjectInfoMap, issuerInfoMap;
01410 
01411     void update(CertContext *c)
01412     {
01413         if(c)
01414         {
01415             subjectInfoMap = orderedToMap(c->props()->subject);
01416             issuerInfoMap = orderedToMap(c->props()->issuer);
01417         }
01418         else
01419         {
01420             subjectInfoMap = CertificateInfo();
01421             issuerInfoMap = CertificateInfo();
01422         }
01423     }
01424 };
01425 
01426 Certificate::Certificate()
01427 :d(new Private)
01428 {
01429 }
01430 
01431 Certificate::Certificate(const QString &fileName)
01432 :d(new Private)
01433 {
01434     *this = fromPEMFile(fileName, 0, QString());
01435 }
01436 
01437 Certificate::Certificate(const CertificateOptions &opts, const PrivateKey &key, const QString &provider)
01438 :d(new Private)
01439 {
01440     CertContext *c = static_cast<CertContext *>(getContext("cert", provider));
01441     if(c->createSelfSigned(opts, *(static_cast<const PKeyContext *>(key.context()))))
01442         change(c);
01443     else
01444         delete c;
01445 }
01446 
01447 Certificate::Certificate(const Certificate &from)
01448 :Algorithm(from), d(from.d)
01449 {
01450 }
01451 
01452 Certificate::~Certificate()
01453 {
01454 }
01455 
01456 Certificate & Certificate::operator=(const Certificate &from)
01457 {
01458     Algorithm::operator=(from);
01459     d = from.d;
01460     return *this;
01461 }
01462 
01463 bool Certificate::isNull() const
01464 {
01465     return (!context() ? true : false);
01466 }
01467 
01468 QDateTime Certificate::notValidBefore() const
01469 {
01470     return static_cast<const CertContext *>(context())->props()->start;
01471 }
01472 
01473 QDateTime Certificate::notValidAfter() const
01474 {
01475     return static_cast<const CertContext *>(context())->props()->end;
01476 }
01477 
01478 CertificateInfo Certificate::subjectInfo() const
01479 {
01480     return d->subjectInfoMap;
01481 }
01482 
01483 CertificateInfoOrdered Certificate::subjectInfoOrdered() const
01484 {
01485     return static_cast<const CertContext *>(context())->props()->subject;
01486 }
01487 
01488 CertificateInfo Certificate::issuerInfo() const
01489 {
01490     return d->issuerInfoMap;
01491 }
01492 
01493 CertificateInfoOrdered Certificate::issuerInfoOrdered() const
01494 {
01495     return static_cast<const CertContext *>(context())->props()->issuer;
01496 }
01497 
01498 Constraints Certificate::constraints() const
01499 {
01500     return static_cast<const CertContext *>(context())->props()->constraints;
01501 }
01502 
01503 QStringList Certificate::policies() const
01504 {
01505     return static_cast<const CertContext *>(context())->props()->policies;
01506 }
01507 
01508 QStringList Certificate::crlLocations() const
01509 {
01510     return static_cast<const CertContext *>(context())->props()->crlLocations;
01511 }
01512 
01513 QStringList Certificate::issuerLocations() const
01514 {
01515     return static_cast<const CertContext *>(context())->props()->issuerLocations;
01516 }
01517 
01518 QStringList Certificate::ocspLocations() const
01519 {
01520     return static_cast<const CertContext *>(context())->props()->ocspLocations;
01521 }
01522 
01523 QString Certificate::commonName() const
01524 {
01525     return d->subjectInfoMap.value(CommonName);
01526 }
01527 
01528 BigInteger Certificate::serialNumber() const
01529 {
01530     return static_cast<const CertContext *>(context())->props()->serial;
01531 }
01532 
01533 PublicKey Certificate::subjectPublicKey() const
01534 {
01535     PKeyContext *c = static_cast<const CertContext *>(context())->subjectPublicKey();
01536     PublicKey key;
01537     key.change(c);
01538     return key;
01539 }
01540 
01541 bool Certificate::isCA() const
01542 {
01543     return static_cast<const CertContext *>(context())->props()->isCA;
01544 }
01545 
01546 bool Certificate::isSelfSigned() const
01547 {
01548     return static_cast<const CertContext *>(context())->props()->isSelfSigned;
01549 }
01550 
01551 bool Certificate::isIssuerOf(const Certificate &other) const
01552 {
01553     const CertContext *cc = static_cast<const CertContext *>(other.context());
01554     return static_cast<const CertContext *>(context())->isIssuerOf(cc);
01555 }
01556 
01557 int Certificate::pathLimit() const
01558 {
01559     return static_cast<const CertContext *>(context())->props()->pathLimit;
01560 }
01561 
01562 SignatureAlgorithm Certificate::signatureAlgorithm() const
01563 {
01564     return static_cast<const CertContext *>(context())->props()->sigalgo;
01565 }
01566 
01567 QByteArray Certificate::subjectKeyId() const
01568 {
01569     return static_cast<const CertContext *>(context())->props()->subjectId;
01570 }
01571 
01572 QByteArray Certificate::issuerKeyId() const
01573 {
01574     return static_cast<const CertContext *>(context())->props()->issuerId;
01575 }
01576 
01577 Validity Certificate::validate(const CertificateCollection &trusted, const CertificateCollection &untrusted, UsageMode u, ValidateFlags vf) const
01578 {
01579     QList<Certificate> issuers = trusted.certificates() + untrusted.certificates();
01580     CertificateChain chain;
01581     chain += *this;
01582     Validity result;
01583     chain = chain.complete(issuers, &result);
01584     if(result != ValidityGood)
01585         return result;
01586     return chain.validate(trusted, untrusted.crls(), u, vf);
01587 }
01588 
01589 QByteArray Certificate::toDER() const
01590 {
01591     return static_cast<const CertContext *>(context())->toDER();
01592 }
01593 
01594 QString Certificate::toPEM() const
01595 {
01596     return static_cast<const CertContext *>(context())->toPEM();
01597 }
01598 
01599 bool Certificate::toPEMFile(const QString &fileName) const
01600 {
01601     return stringToFile(fileName, toPEM());
01602 }
01603 
01604 Certificate Certificate::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider)
01605 {
01606     Certificate c;
01607     CertContext *cc = static_cast<CertContext *>(getContext("cert", provider));
01608     ConvertResult r = cc->fromDER(a);
01609     if(result)
01610         *result = r;
01611     if(r == ConvertGood)
01612         c.change(cc);
01613     else
01614         delete cc;
01615     return c;
01616 }
01617 
01618 Certificate Certificate::fromPEM(const QString &s, ConvertResult *result, const QString &provider)
01619 {
01620     Certificate c;
01621     CertContext *cc = static_cast<CertContext *>(getContext("cert", provider));
01622     ConvertResult r = cc->fromPEM(s);
01623     if(result)
01624         *result = r;
01625     if(r == ConvertGood)
01626         c.change(cc);
01627     else
01628         delete cc;
01629     return c;
01630 }
01631 
01632 Certificate Certificate::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider)
01633 {
01634     QString pem;
01635     if(!stringFromFile(fileName, &pem))
01636     {
01637         if(result)
01638             *result = ErrorFile;
01639         return Certificate();
01640     }
01641     return fromPEM(pem, result, provider);
01642 }
01643 
01644 // check for ip addresses in iPAddress, dNSName, then commonName
01645 // for all else, check in dNSName, then commonName
01646 bool Certificate::matchesHostName(const QString &host) const
01647 {
01648     QByteArray ipaddr = ipaddr_str2bin(host);
01649     if(!ipaddr.isEmpty()) // ip address
01650     {
01651         // check iPAddress
01652         foreach(const QString &s, subjectInfo().values(IPAddress))
01653         {
01654             if(cert_match_ipaddress(s, ipaddr))
01655                 return true;
01656         }
01657 
01658         // check dNSName
01659         foreach(const QString &s, subjectInfo().values(DNS))
01660         {
01661             if(cert_match_ipaddress(s, ipaddr))
01662                 return true;
01663         }
01664 
01665         // check commonName
01666         foreach(const QString &s, subjectInfo().values(CommonName))
01667         {
01668             if(cert_match_ipaddress(s, ipaddr))
01669                 return true;
01670         }
01671     }
01672     else // domain
01673     {
01674         // lowercase
01675         QString name = host.toLower();
01676 
01677         // ACE
01678         name = QString::fromLatin1(QUrl::toAce(name));
01679 
01680         // don't allow wildcards in the comparison host
01681         if(name.contains('*'))
01682             return false;
01683 
01684         // strip out trailing dot
01685         if(name.length() > 0 && name[name.length()-1] == '.')
01686             name.truncate(name.length()-1);
01687 
01688         // make sure the name is not empty after our modifications
01689         if(name.isEmpty())
01690             return false;
01691 
01692         // check dNSName
01693         foreach(const QString &s, subjectInfo().values(DNS))
01694         {
01695             if(cert_match_domain(s, name))
01696                 return true;
01697         }
01698 
01699         // check commonName
01700         foreach(const QString &s, subjectInfo().values(CommonName))
01701         {
01702             if(cert_match_domain(s, name))
01703                 return true;
01704         }
01705     }
01706 
01707     return false;
01708 }
01709 
01710 bool Certificate::operator==(const Certificate &otherCert) const
01711 {
01712     if(isNull())
01713     {
01714         if(otherCert.isNull())
01715             return true;
01716         else
01717             return false;
01718     }
01719     else if(otherCert.isNull())
01720         return false;
01721 
01722     const CertContext *other = static_cast<const CertContext *>(otherCert.context());
01723     return static_cast<const CertContext *>(context())->compare(other);
01724 }
01725 
01726 void Certificate::change(CertContext *c)
01727 {
01728     Algorithm::change(c);
01729     d->update(static_cast<CertContext *>(context()));
01730 }
01731 
01732 Validity Certificate::chain_validate(const CertificateChain &chain, const CertificateCollection &trusted, const QList<CRL> &untrusted_crls, UsageMode u, ValidateFlags vf) const
01733 {
01734     QList<CertContext*> chain_list;
01735     QList<CertContext*> trusted_list;
01736     QList<CRLContext*> crl_list;
01737 
01738     QList<Certificate> chain_certs = chain;
01739     QList<Certificate> trusted_certs = trusted.certificates();
01740     QList<CRL> crls = trusted.crls() + untrusted_crls;
01741 
01742     for(int n = 0; n < chain_certs.count(); ++n)
01743     {
01744         CertContext *c = static_cast<CertContext *>(chain_certs[n].context());
01745         chain_list += c;
01746     }
01747     for(int n = 0; n < trusted_certs.count(); ++n)
01748     {
01749         CertContext *c = static_cast<CertContext *>(trusted_certs[n].context());
01750         trusted_list += c;
01751     }
01752     for(int n = 0; n < crls.count(); ++n)
01753     {
01754         CRLContext *c = static_cast<CRLContext *>(crls[n].context());
01755         crl_list += c;
01756     }
01757 
01758     return static_cast<const CertContext *>(context())->validate_chain(chain_list, trusted_list, crl_list, u, vf);
01759 }
01760 
01761 CertificateChain Certificate::chain_complete(const CertificateChain &chain, const QList<Certificate> &issuers, Validity *result) const
01762 {
01763     CertificateChain out;
01764     QList<Certificate> pool = issuers + chain.mid(1);
01765     out += chain.first();
01766     if(result)
01767         *result = ValidityGood;
01768     while(!out.last().isSelfSigned())
01769     {
01770         // try to get next in chain
01771         int at = -1;
01772         for(int n = 0; n < pool.count(); ++n)
01773         {
01774             //QString str = QString("[%1] issued by [%2] ? ").arg(out.last().commonName()).arg(pool[n].commonName());
01775             if(pool[n].isIssuerOf(out.last()))
01776             {
01777                 //printf("%s  yes\n", qPrintable(str));
01778                 at = n;
01779                 break;
01780             }
01781             //printf("%s  no\n", qPrintable(str));
01782         }
01783         if(at == -1)
01784         {
01785             if(result)
01786                 *result = ErrorInvalidCA;
01787             break;
01788         }
01789 
01790         // take it out of the pool
01791         Certificate next = pool.takeAt(at);
01792 
01793         // make sure it isn't in the chain already (avoid loops)
01794         if(out.contains(next))
01795             break;
01796 
01797         // append to the chain
01798         out += next;
01799     }
01800     return out;
01801 }
01802 
01803 //----------------------------------------------------------------------------
01804 // CertificateRequest
01805 //----------------------------------------------------------------------------
01806 class CertificateRequest::Private : public QSharedData
01807 {
01808 public:
01809     CertificateInfo subjectInfoMap;
01810 
01811     void update(CSRContext *c)
01812     {
01813         if(c)
01814             subjectInfoMap = orderedToMap(c->props()->subject);
01815         else
01816             subjectInfoMap = CertificateInfo();
01817     }
01818 };
01819 
01820 CertificateRequest::CertificateRequest()
01821 :d(new Private)
01822 {
01823 }
01824 
01825 CertificateRequest::CertificateRequest(const QString &fileName)
01826 :d(new Private)
01827 {
01828     *this = fromPEMFile(fileName, 0, QString());
01829 }
01830 
01831 CertificateRequest::CertificateRequest(const CertificateOptions &opts, const PrivateKey &key, const QString &provider)
01832 :d(new Private)
01833 {
01834     CSRContext *c = static_cast<CSRContext *>(getContext("csr", provider));
01835     if(c->createRequest(opts, *(static_cast<const PKeyContext *>(key.context()))))
01836         change(c);
01837     else
01838         delete c;
01839 }
01840 
01841 CertificateRequest::CertificateRequest(const CertificateRequest &from)
01842 :Algorithm(from), d(from.d)
01843 {
01844 }
01845 
01846 CertificateRequest::~CertificateRequest()
01847 {
01848 }
01849 
01850 CertificateRequest & CertificateRequest::operator=(const CertificateRequest &from)
01851 {
01852     Algorithm::operator=(from);
01853     d = from.d;
01854     return *this;
01855 }
01856 
01857 bool CertificateRequest::isNull() const
01858 {
01859     return (!context() ? true : false);
01860 }
01861 
01862 bool CertificateRequest::canUseFormat(CertificateRequestFormat f, const QString &provider)
01863 {
01864     CSRContext *c = static_cast<CSRContext *>(getContext("csr", provider));
01865     bool ok = c->canUseFormat(f);
01866     delete c;
01867     return ok;
01868 }
01869 
01870 CertificateRequestFormat CertificateRequest::format() const
01871 {
01872     if(isNull())
01873         return PKCS10; // some default so we don't explode
01874     return static_cast<const CSRContext *>(context())->props()->format;
01875 }
01876 
01877 CertificateInfo CertificateRequest::subjectInfo() const
01878 {
01879     return d->subjectInfoMap;
01880 }
01881 
01882 CertificateInfoOrdered CertificateRequest::subjectInfoOrdered() const
01883 {
01884     return static_cast<const CSRContext *>(context())->props()->subject;
01885 }
01886 
01887 Constraints CertificateRequest::constraints() const
01888 {
01889     return static_cast<const CSRContext *>(context())->props()->constraints;
01890 }
01891 
01892 QStringList CertificateRequest::policies() const
01893 {
01894     return static_cast<const CSRContext *>(context())->props()->policies;
01895 }
01896 
01897 PublicKey CertificateRequest::subjectPublicKey() const
01898 {
01899     PKeyContext *c = static_cast<const CSRContext *>(context())->subjectPublicKey();
01900     PublicKey key;
01901     key.change(c);
01902     return key;
01903 }
01904 
01905 bool CertificateRequest::isCA() const
01906 {
01907     return static_cast<const CSRContext *>(context())->props()->isCA;
01908 }
01909 
01910 int CertificateRequest::pathLimit() const
01911 {
01912     return static_cast<const CSRContext *>(context())->props()->pathLimit;
01913 }
01914 
01915 QString CertificateRequest::challenge() const
01916 {
01917     return static_cast<const CSRContext *>(context())->props()->challenge;
01918 }
01919 
01920 SignatureAlgorithm CertificateRequest::signatureAlgorithm() const
01921 {
01922     return static_cast<const CSRContext *>(context())->props()->sigalgo;
01923 }
01924 
01925 bool CertificateRequest::operator==(const CertificateRequest &otherCsr) const
01926 {
01927     if(isNull())
01928     {
01929         if(otherCsr.isNull())
01930             return true;
01931         else
01932             return false;
01933     }
01934     else if(otherCsr.isNull())
01935         return false;
01936 
01937     const CSRContext *other = static_cast<const CSRContext *>(otherCsr.context());
01938     return static_cast<const CSRContext *>(context())->compare(other);
01939 }
01940 
01941 QByteArray CertificateRequest::toDER() const
01942 {
01943     return static_cast<const CSRContext *>(context())->toDER();
01944 }
01945 
01946 QString CertificateRequest::toPEM() const
01947 {
01948     return static_cast<const CSRContext *>(context())->toPEM();
01949 }
01950 
01951 bool CertificateRequest::toPEMFile(const QString &fileName) const
01952 {
01953     return stringToFile(fileName, toPEM());
01954 }
01955 
01956 CertificateRequest CertificateRequest::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider)
01957 {
01958     CertificateRequest c;
01959     CSRContext *csr = static_cast<CSRContext *>(getContext("csr", provider));
01960     ConvertResult r = csr->fromDER(a);
01961     if(result)
01962         *result = r;
01963     if(r == ConvertGood)
01964         c.change(csr);
01965     else
01966         delete csr;
01967     return c;
01968 }
01969 
01970 CertificateRequest CertificateRequest::fromPEM(const QString &s, ConvertResult *result, const QString &provider)
01971 {
01972     CertificateRequest c;
01973     CSRContext *csr = static_cast<CSRContext *>(getContext("csr", provider));
01974     ConvertResult r = csr->fromPEM(s);
01975     if(result)
01976         *result = r;
01977     if(r == ConvertGood)
01978         c.change(csr);
01979     else
01980         delete csr;
01981     return c;
01982 }
01983 
01984 CertificateRequest CertificateRequest::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider)
01985 {
01986     QString pem;
01987     if(!stringFromFile(fileName, &pem))
01988     {
01989         if(result)
01990             *result = ErrorFile;
01991         return CertificateRequest();
01992     }
01993     return fromPEM(pem, result, provider);
01994 }
01995 
01996 QString CertificateRequest::toString() const
01997 {
01998     return static_cast<const CSRContext *>(context())->toSPKAC();
01999 }
02000 
02001 CertificateRequest CertificateRequest::fromString(const QString &s, ConvertResult *result, const QString &provider)
02002 {
02003     CertificateRequest c;
02004     CSRContext *csr = static_cast<CSRContext *>(getContext("csr", provider));
02005     ConvertResult r = csr->fromSPKAC(s);
02006     if(result)
02007         *result = r;
02008     if(r == ConvertGood)
02009         c.change(csr);
02010     else
02011         delete csr;
02012     return c;
02013 }
02014 
02015 void CertificateRequest::change(CSRContext *c)
02016 {
02017     Algorithm::change(c);
02018     d->update(static_cast<CSRContext *>(context()));
02019 }
02020 
02021 //----------------------------------------------------------------------------
02022 // CRLEntry
02023 //----------------------------------------------------------------------------
02024 CRLEntry::CRLEntry()
02025 {
02026     _reason = Unspecified;
02027 }
02028 
02029 CRLEntry::CRLEntry(const Certificate &c, Reason r)
02030 {
02031     _serial = c.serialNumber();
02032     _time = QDateTime::currentDateTime();
02033     _reason = r;
02034 }
02035 
02036 CRLEntry::CRLEntry(const BigInteger serial, const QDateTime &time, Reason r)
02037 {
02038     _serial = serial;
02039     _time = time;
02040     _reason = r;
02041 }
02042 
02043 CRLEntry::CRLEntry(const CRLEntry &from)
02044 :_serial(from._serial), _time(from._time), _reason(from._reason)
02045 {
02046 }
02047 
02048 CRLEntry::~CRLEntry()
02049 {
02050 }
02051 
02052 CRLEntry & CRLEntry::operator=(const CRLEntry &from)
02053 {
02054     _serial = from._serial;
02055     _time = from._time;
02056     _reason = from._reason;
02057     return *this;
02058 }
02059 
02060 bool CRLEntry::isNull() const
02061 {
02062     return (_time.isNull());
02063 }
02064 
02065 BigInteger CRLEntry::serialNumber() const
02066 {
02067     return _serial;
02068 }
02069 
02070 QDateTime CRLEntry::time() const
02071 {
02072     return _time;
02073 }
02074 
02075 CRLEntry::Reason CRLEntry::reason() const
02076 {
02077     return _reason;
02078 }
02079 
02080 bool CRLEntry::operator==(const CRLEntry &otherEntry) const
02081 {
02082     if(isNull())
02083     {
02084         if(otherEntry.isNull())
02085             return true;
02086         else
02087             return false;
02088     }
02089     else if(otherEntry.isNull())
02090         return false;
02091 
02092     if((_serial != otherEntry._serial) ||
02093         (_time != otherEntry._time) ||
02094         (_reason != otherEntry._reason))
02095     {
02096         return false;
02097     }
02098     return true;
02099 }
02100 
02101 bool CRLEntry::operator<(const CRLEntry &otherEntry) const
02102 {
02103     if(isNull() || otherEntry.isNull())
02104         return false;
02105 
02106     if(_serial < otherEntry._serial)
02107         return true;
02108 
02109     return false;
02110 }
02111 
02112 //----------------------------------------------------------------------------
02113 // CRL
02114 //----------------------------------------------------------------------------
02115 class CRL::Private : public QSharedData
02116 {
02117 public:
02118     CertificateInfo issuerInfoMap;
02119 
02120     void update(CRLContext *c)
02121     {
02122         if(c)
02123             issuerInfoMap = orderedToMap(c->props()->issuer);
02124         else
02125             issuerInfoMap = CertificateInfo();
02126     }
02127 };
02128 
02129 CRL::CRL()
02130 :d(new Private)
02131 {
02132 }
02133 
02134 CRL::CRL(const CRL &from)
02135 :Algorithm(from), d(from.d)
02136 {
02137 }
02138 
02139 CRL::~CRL()
02140 {
02141 }
02142 
02143 CRL & CRL::operator=(const CRL &from)
02144 {
02145     Algorithm::operator=(from);
02146     d = from.d;
02147     return *this;
02148 }
02149 
02150 bool CRL::isNull() const
02151 {
02152     return (!context() ? true : false);
02153 }
02154 
02155 CertificateInfo CRL::issuerInfo() const
02156 {
02157     return d->issuerInfoMap;
02158 }
02159 
02160 CertificateInfoOrdered CRL::issuerInfoOrdered() const
02161 {
02162     return static_cast<const CRLContext *>(context())->props()->issuer;
02163 }
02164 
02165 int CRL::number() const
02166 {
02167     return static_cast<const CRLContext *>(context())->props()->number;
02168 }
02169 
02170 QDateTime CRL::thisUpdate() const
02171 {
02172     return static_cast<const CRLContext *>(context())->props()->thisUpdate;
02173 }
02174 
02175 QDateTime CRL::nextUpdate() const
02176 {
02177     return static_cast<const CRLContext *>(context())->props()->nextUpdate;
02178 }
02179 
02180 QList<CRLEntry> CRL::revoked() const
02181 {
02182     return static_cast<const CRLContext *>(context())->props()->revoked;
02183 }
02184 
02185 SignatureAlgorithm CRL::signatureAlgorithm() const
02186 {
02187     return static_cast<const CRLContext *>(context())->props()->sigalgo;
02188 }
02189 
02190 QByteArray CRL::issuerKeyId() const
02191 {
02192     return static_cast<const CRLContext *>(context())->props()->issuerId;
02193 }
02194 
02195 QByteArray CRL::toDER() const
02196 {
02197     return static_cast<const CRLContext *>(context())->toDER();
02198 }
02199 
02200 QString CRL::toPEM() const
02201 {
02202     return static_cast<const CRLContext *>(context())->toPEM();
02203 }
02204 
02205 bool CRL::operator==(const CRL &otherCrl) const
02206 {
02207     if(isNull())
02208     {
02209         if(otherCrl.isNull())
02210             return true;
02211         else
02212             return false;
02213     }
02214     else if(otherCrl.isNull())
02215         return false;
02216 
02217     const CRLContext *other = static_cast<const CRLContext *>(otherCrl.context());
02218     return static_cast<const CRLContext *>(context())->compare(other);
02219 }
02220 
02221 CRL CRL::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider)
02222 {
02223     CRL c;
02224     CRLContext *cc = static_cast<CRLContext *>(getContext("crl", provider));
02225     ConvertResult r = cc->fromDER(a);
02226     if(result)
02227         *result = r;
02228     if(r == ConvertGood)
02229         c.change(cc);
02230     else
02231         delete cc;
02232     return c;
02233 }
02234 
02235 CRL CRL::fromPEM(const QString &s, ConvertResult *result, const QString &provider)
02236 {
02237     CRL c;
02238     CRLContext *cc = static_cast<CRLContext *>(getContext("crl", provider));
02239     ConvertResult r = cc->fromPEM(s);
02240     if(result)
02241         *result = r;
02242     if(r == ConvertGood)
02243         c.change(cc);
02244     else
02245         delete cc;
02246     return c;
02247 }
02248 
02249 CRL CRL::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider)
02250 {
02251     QString pem;
02252     if(!stringFromFile(fileName, &pem))
02253     {
02254         if(result)
02255             *result = ErrorFile;
02256         return CRL();
02257     }
02258     return fromPEM(pem, result, provider);
02259 }
02260 
02261 bool CRL::toPEMFile(const QString &fileName) const
02262 {
02263     return stringToFile(fileName, toPEM());
02264 }
02265 
02266 void CRL::change(CRLContext *c)
02267 {
02268     Algorithm::change(c);
02269     d->update(static_cast<CRLContext *>(context()));
02270 }
02271 
02272 //----------------------------------------------------------------------------
02273 // Store
02274 //----------------------------------------------------------------------------
02275 // CRL / X509 CRL
02276 // CERTIFICATE / X509 CERTIFICATE
02277 static QString readNextPem(QTextStream *ts, bool *isCRL)
02278 {
02279     QString pem;
02280     bool crl = false;
02281     bool found = false;
02282     bool done = false;
02283     while(!ts->atEnd())
02284     {
02285         QString line = ts->readLine();
02286         if(!found)
02287         {
02288             if(line.startsWith("-----BEGIN "))
02289             {
02290                 if(line.contains("CERTIFICATE"))
02291                 {
02292                     found = true;
02293                     pem += line + '\n';
02294                     crl = false;
02295                 }
02296                 else if(line.contains("CRL"))
02297                 {
02298                     found = true;
02299                     pem += line + '\n';
02300                     crl = true;
02301                 }
02302             }
02303         }
02304         else
02305         {
02306             pem += line + '\n';
02307             if(line.startsWith("-----END "))
02308             {
02309                 done = true;
02310                 break;
02311             }
02312         }
02313     }
02314     if(!done)
02315                 return QString();
02316     if(isCRL)
02317         *isCRL = crl;
02318     return pem;
02319 }
02320 
02321 class CertificateCollection::Private : public QSharedData
02322 {
02323 public:
02324     QList<Certificate> certs;
02325     QList<CRL> crls;
02326 };
02327 
02328 CertificateCollection::CertificateCollection()
02329 :d(new Private)
02330 {
02331 }
02332 
02333 CertificateCollection::CertificateCollection(const CertificateCollection &from)
02334 :d(from.d)
02335 {
02336 }
02337 
02338 CertificateCollection::~CertificateCollection()
02339 {
02340 }
02341 
02342 CertificateCollection & CertificateCollection::operator=(const CertificateCollection &from)
02343 {
02344     d = from.d;
02345     return *this;
02346 }
02347 
02348 void CertificateCollection::addCertificate(const Certificate &cert)
02349 {
02350     d->certs.append(cert);
02351 }
02352 
02353 void CertificateCollection::addCRL(const CRL &crl)
02354 {
02355     d->crls.append(crl);
02356 }
02357 
02358 QList<Certificate> CertificateCollection::certificates() const
02359 {
02360     return d->certs;
02361 }
02362 
02363 QList<CRL> CertificateCollection::crls() const
02364 {
02365     return d->crls;
02366 }
02367 
02368 void CertificateCollection::append(const CertificateCollection &other)
02369 {
02370     d->certs += other.d->certs;
02371     d->crls += other.d->crls;
02372 }
02373 
02374 CertificateCollection CertificateCollection::operator+(const CertificateCollection &other) const
02375 {
02376     CertificateCollection c = *this;
02377     c.append(other);
02378     return c;
02379 }
02380 
02381 CertificateCollection & CertificateCollection::operator+=(const CertificateCollection &other)
02382 {
02383     append(other);
02384     return *this;
02385 }
02386 
02387 bool CertificateCollection::canUsePKCS7(const QString &provider)
02388 {
02389     return isSupported("certcollection", provider);
02390 }
02391 
02392 bool CertificateCollection::toFlatTextFile(const QString &fileName)
02393 {
02394     QFile f(fileName);
02395     if(!f.open(QFile::WriteOnly))
02396         return false;
02397 
02398     QTextStream ts(&f);
02399     int n;
02400     for(n = 0; n < d->certs.count(); ++n)
02401         ts << d->certs[n].toPEM();
02402     for(n = 0; n < d->crls.count(); ++n)
02403         ts << d->crls[n].toPEM();
02404     return true;
02405 }
02406 
02407 bool CertificateCollection::toPKCS7File(const QString &fileName, const QString &provider)
02408 {
02409     CertCollectionContext *col = static_cast<CertCollectionContext *>(getContext("certcollection", provider));
02410 
02411     QList<CertContext*> cert_list;
02412     QList<CRLContext*> crl_list;
02413     int n;
02414     for(n = 0; n < d->certs.count(); ++n)
02415     {
02416         CertContext *c = static_cast<CertContext *>(d->certs[n].context());
02417         cert_list += c;
02418     }
02419     for(n = 0; n < d->crls.count(); ++n)
02420     {
02421         CRLContext *c = static_cast<CRLContext *>(d->crls[n].context());
02422         crl_list += c;
02423     }
02424 
02425     QByteArray result = col->toPKCS7(cert_list, crl_list);
02426     delete col;
02427 
02428     return arrayToFile(fileName, result);
02429 }
02430 
02431 CertificateCollection CertificateCollection::fromFlatTextFile(const QString &fileName, ConvertResult *result, const QString &provider)
02432 {
02433     QFile f(fileName);
02434     if(!f.open(QFile::ReadOnly))
02435     {
02436         if(result)
02437             *result = ErrorFile;
02438         return CertificateCollection();
02439     }
02440 
02441     CertificateCollection certs;
02442     QTextStream ts(&f);
02443     while(1)
02444     {
02445         bool isCRL = false;
02446         QString pem = readNextPem(&ts, &isCRL);
02447         if(pem.isNull())
02448             break;
02449         if(isCRL)
02450         {
02451             CRL c = CRL::fromPEM(pem, 0, provider);
02452             if(!c.isNull())
02453                 certs.addCRL(c);
02454         }
02455         else
02456         {
02457             Certificate c = Certificate::fromPEM(pem, 0, provider);
02458             if(!c.isNull())
02459                 certs.addCertificate(c);
02460         }
02461     }
02462 
02463     if(result)
02464         *result = ConvertGood;
02465 
02466     return certs;
02467 }
02468 
02469 CertificateCollection CertificateCollection::fromPKCS7File(const QString &fileName, ConvertResult *result, const QString &provider)
02470 {
02471     QByteArray der;
02472     if(!arrayFromFile(fileName, &der))
02473     {
02474         if(result)
02475             *result = ErrorFile;
02476         return CertificateCollection();
02477     }
02478 
02479     CertificateCollection certs;
02480 
02481     QList<CertContext*> cert_list;
02482     QList<CRLContext*> crl_list;
02483     CertCollectionContext *col = static_cast<CertCollectionContext *>(getContext("certcollection", provider));
02484     ConvertResult r = col->fromPKCS7(der, &cert_list, &crl_list);
02485     delete col;
02486 
02487     if(result)
02488         *result = r;
02489     if(r == ConvertGood)
02490     {
02491         int n;
02492         for(n = 0; n < cert_list.count(); ++n)
02493         {
02494             Certificate c;
02495             c.change(cert_list[n]);
02496             certs.addCertificate(c);
02497         }
02498         for(n = 0; n < crl_list.count(); ++n)
02499         {
02500             CRL c;
02501             c.change(crl_list[n]);
02502             certs.addCRL(c);
02503         }
02504     }
02505     return certs;
02506 }
02507 
02508 //----------------------------------------------------------------------------
02509 // CertificateAuthority
02510 //----------------------------------------------------------------------------
02511 CertificateAuthority::CertificateAuthority(const Certificate &cert, const PrivateKey &key, const QString &provider)
02512 :Algorithm("ca", provider)
02513 {
02514     static_cast<CAContext *>(context())->setup(*(static_cast<const CertContext *>(cert.context())), *(static_cast<const PKeyContext *>(key.context())));
02515 }
02516 
02517 CertificateAuthority::CertificateAuthority(const CertificateAuthority &from)
02518 :Algorithm(from)
02519 {
02520 }
02521 
02522 CertificateAuthority::~CertificateAuthority()
02523 {
02524 }
02525 
02526 CertificateAuthority & CertificateAuthority::operator=(const CertificateAuthority &from)
02527 {
02528     Algorithm::operator=(from);
02529     return *this;
02530 }
02531 
02532 Certificate CertificateAuthority::certificate() const
02533 {
02534     Certificate c;
02535     c.change(static_cast<const CAContext *>(context())->certificate());
02536     return c;
02537 }
02538 
02539 Certificate CertificateAuthority::signRequest(const CertificateRequest &req, const QDateTime &notValidAfter) const
02540 {
02541     Certificate c;
02542     CertContext *cc = static_cast<const CAContext *>(context())->signRequest(*(static_cast<const CSRContext *>(req.context())), notValidAfter);
02543     if(cc)
02544         c.change(cc);
02545     return c;
02546 }
02547 
02548 CRL CertificateAuthority::createCRL(const QDateTime &nextUpdate) const
02549 {
02550     CRL crl;
02551     CRLContext *cc = static_cast<const CAContext *>(context())->createCRL(nextUpdate);
02552     if(cc)
02553         crl.change(cc);
02554     return crl;
02555 }
02556 
02557 CRL CertificateAuthority::updateCRL(const CRL &crl, const QList<CRLEntry> &entries, const QDateTime &nextUpdate) const
02558 {
02559     CRL new_crl;
02560     CRLContext *cc = static_cast<const CAContext *>(context())->updateCRL(*(static_cast<const CRLContext *>(crl.context())), entries, nextUpdate);
02561     if(cc)
02562         new_crl.change(cc);
02563     return new_crl;
02564 }
02565 
02566 //----------------------------------------------------------------------------
02567 // KeyBundle
02568 //----------------------------------------------------------------------------
02569 class KeyBundle::Private : public QSharedData
02570 {
02571 public:
02572     QString name;
02573     CertificateChain chain;
02574     PrivateKey key;
02575 };
02576 
02577 KeyBundle::KeyBundle()
02578 :d(new Private)
02579 {
02580 }
02581 
02582 KeyBundle::KeyBundle(const QString &fileName, const SecureArray &passphrase)
02583 :d(new Private)
02584 {
02585     *this = fromFile(fileName, passphrase, 0, QString());
02586 }
02587 
02588 KeyBundle::KeyBundle(const KeyBundle &from)
02589 :d(from.d)
02590 {
02591 }
02592 
02593 KeyBundle::~KeyBundle()
02594 {
02595 }
02596 
02597 KeyBundle & KeyBundle::operator=(const KeyBundle &from)
02598 {
02599     d = from.d;
02600     return *this;
02601 }
02602 
02603 bool KeyBundle::isNull() const
02604 {
02605     return d->chain.isEmpty();
02606 }
02607 
02608 QString KeyBundle::name() const
02609 {
02610     return d->name;
02611 }
02612 
02613 CertificateChain KeyBundle::certificateChain() const
02614 {
02615     return d->chain;
02616 }
02617 
02618 PrivateKey KeyBundle::privateKey() const
02619 {
02620     return d->key;
02621 }
02622 
02623 void KeyBundle::setName(const QString &s)
02624 {
02625     d->name = s;
02626 }
02627 
02628 void KeyBundle::setCertificateChainAndKey(const CertificateChain &c, const PrivateKey &key)
02629 {
02630     d->chain = c;
02631     d->key = key;
02632 }
02633 
02634 QByteArray KeyBundle::toArray(const SecureArray &passphrase, const QString &provider) const
02635 {
02636     PKCS12Context *pix = static_cast<PKCS12Context *>(getContext("pkcs12", provider));
02637 
02638     QList<const CertContext*> list;
02639     for(int n = 0; n < d->chain.count(); ++n)
02640         list.append(static_cast<const CertContext *>(d->chain[n].context()));
02641     QByteArray buf = pix->toPKCS12(d->name, list, *(static_cast<const PKeyContext *>(d->key.context())), passphrase);
02642     delete pix;
02643 
02644     return buf;
02645 }
02646 
02647 bool KeyBundle::toFile(const QString &fileName, const SecureArray &passphrase, const QString &provider) const
02648 {
02649     return arrayToFile(fileName, toArray(passphrase, provider));
02650 }
02651 
02652 KeyBundle KeyBundle::fromArray(const QByteArray &a, const SecureArray &passphrase, ConvertResult *result, const QString &provider)
02653 {
02654     KeyBundle bundle;
02655     get_pkcs12_der(a, QString(), (void *)&a, passphrase, result, provider, &bundle.d->name, &bundle.d->chain, &bundle.d->key);
02656     return bundle;
02657 }
02658 
02659 KeyBundle KeyBundle::fromFile(const QString &fileName, const SecureArray &passphrase, ConvertResult *result, const QString &provider)
02660 {
02661     QByteArray der;
02662     if(!arrayFromFile(fileName, &der))
02663     {
02664         if(result)
02665             *result = ErrorFile;
02666         return KeyBundle();
02667     }
02668 
02669     KeyBundle bundle;
02670     get_pkcs12_der(der, fileName, 0, passphrase, result, provider, &bundle.d->name, &bundle.d->chain, &bundle.d->key);
02671     return bundle;
02672 }
02673 
02674 //----------------------------------------------------------------------------
02675 // PGPKey
02676 //----------------------------------------------------------------------------
02677 PGPKey::PGPKey()
02678 {
02679 }
02680 
02681 PGPKey::PGPKey(const QString &fileName)
02682 {
02683     *this = fromFile(fileName, 0, QString());
02684 }
02685 
02686 PGPKey::PGPKey(const PGPKey &from)
02687 :Algorithm(from)
02688 {
02689 }
02690 
02691 PGPKey::~PGPKey()
02692 {
02693 }
02694 
02695 PGPKey & PGPKey::operator=(const PGPKey &from)
02696 {
02697     Algorithm::operator=(from);
02698     return *this;
02699 }
02700 
02701 bool PGPKey::isNull() const
02702 {
02703     return (!context() ? true : false);
02704 }
02705 
02706 QString PGPKey::keyId() const
02707 {
02708     return static_cast<const PGPKeyContext *>(context())->props()->keyId;
02709 }
02710 
02711 QString PGPKey::primaryUserId() const
02712 {
02713     return static_cast<const PGPKeyContext *>(context())->props()->userIds.first();
02714 }
02715 
02716 QStringList PGPKey::userIds() const
02717 {
02718     return static_cast<const PGPKeyContext *>(context())->props()->userIds;
02719 }
02720 
02721 bool PGPKey::isSecret() const
02722 {
02723     return static_cast<const PGPKeyContext *>(context())->props()->isSecret;
02724 }
02725 
02726 QDateTime PGPKey::creationDate() const
02727 {
02728     return static_cast<const PGPKeyContext *>(context())->props()->creationDate;
02729 }
02730 
02731 QDateTime PGPKey::expirationDate() const
02732 {
02733     return static_cast<const PGPKeyContext *>(context())->props()->expirationDate;
02734 }
02735 
02736 QString PGPKey::fingerprint() const
02737 {
02738     return static_cast<const PGPKeyContext *>(context())->props()->fingerprint;
02739 }
02740 
02741 bool PGPKey::inKeyring() const
02742 {
02743     return static_cast<const PGPKeyContext *>(context())->props()->inKeyring;
02744 }
02745 
02746 bool PGPKey::isTrusted() const
02747 {
02748     return static_cast<const PGPKeyContext *>(context())->props()->isTrusted;
02749 }
02750 
02751 QByteArray PGPKey::toArray() const
02752 {
02753     return static_cast<const PGPKeyContext *>(context())->toBinary();
02754 }
02755 
02756 QString PGPKey::toString() const
02757 {
02758     return static_cast<const PGPKeyContext *>(context())->toAscii();
02759 }
02760 
02761 bool PGPKey::toFile(const QString &fileName) const
02762 {
02763     return stringToFile(fileName, toString());
02764 }
02765 
02766 PGPKey PGPKey::fromArray(const QByteArray &a, ConvertResult *result, const QString &provider)
02767 {
02768     PGPKey k;
02769     PGPKeyContext *kc = static_cast<PGPKeyContext *>(getContext("pgpkey", provider));
02770     ConvertResult r = kc->fromBinary(a);
02771     if(result)
02772         *result = r;
02773     if(r == ConvertGood)
02774         k.change(kc);
02775     else
02776         delete kc;
02777     return k;
02778 }
02779 
02780 PGPKey PGPKey::fromString(const QString &s, ConvertResult *result, const QString &provider)
02781 {
02782     PGPKey k;
02783     PGPKeyContext *kc = static_cast<PGPKeyContext *>(getContext("pgpkey", provider));
02784     ConvertResult r = kc->fromAscii(s);
02785     if(result)
02786         *result = r;
02787     if(r == ConvertGood)
02788         k.change(kc);
02789     else
02790         delete kc;
02791     return k;
02792 }
02793 
02794 PGPKey PGPKey::fromFile(const QString &fileName, ConvertResult *result, const QString &provider)
02795 {
02796     QString str;
02797     if(!stringFromFile(fileName, &str))
02798     {
02799         if(result)
02800             *result = ErrorFile;
02801         return PGPKey();
02802     }
02803     return fromString(str, result, provider);
02804 }
02805 
02806 //----------------------------------------------------------------------------
02807 // KeyLoader
02808 //----------------------------------------------------------------------------
02809 class KeyLoaderThread : public QThread
02810 {
02811     Q_OBJECT
02812 public:
02813     enum Type { PKPEMFile, PKPEM, PKDER, KBDERFile, KBDER };
02814 
02815     class In
02816     {
02817     public:
02818         Type type;
02819         QString fileName, pem;
02820         SecureArray der;
02821         QByteArray kbder;
02822     };
02823 
02824     class Out
02825     {
02826     public:
02827         ConvertResult convertResult;
02828         PrivateKey privateKey;
02829         KeyBundle keyBundle;
02830     };
02831 
02832     In in;
02833     Out out;
02834 
02835     KeyLoaderThread(QObject *parent = 0) : QThread(parent)
02836     {
02837     }
02838 
02839 protected:
02840     virtual void run()
02841     {
02842         if(in.type == PKPEMFile)
02843             out.privateKey = PrivateKey::fromPEMFile(in.fileName, SecureArray(), &out.convertResult);
02844         else if(in.type == PKPEM)
02845             out.privateKey = PrivateKey::fromPEM(in.pem, SecureArray(), &out.convertResult);
02846         else if(in.type == PKDER)
02847             out.privateKey = PrivateKey::fromDER(in.der, SecureArray(), &out.convertResult);
02848         else if(in.type == KBDERFile)
02849             out.keyBundle = KeyBundle::fromFile(in.fileName, SecureArray(), &out.convertResult);
02850         else if(in.type == KBDER)
02851             out.keyBundle = KeyBundle::fromArray(in.kbder, SecureArray(), &out.convertResult);
02852     }
02853 };
02854 
02855 class KeyLoader::Private : public QObject
02856 {
02857     Q_OBJECT
02858 public:
02859     KeyLoader *q;
02860 
02861     bool active;
02862     KeyLoaderThread *thread;
02863     KeyLoaderThread::In in;
02864     KeyLoaderThread::Out out;
02865 
02866     Private(KeyLoader *_q) : QObject(_q), q(_q)
02867     {
02868         active = false;
02869     }
02870 
02871     void reset()
02872     {
02873         in = KeyLoaderThread::In();
02874         out = KeyLoaderThread::Out();
02875     }
02876 
02877     void start()
02878     {
02879         active = true;
02880         thread = new KeyLoaderThread(this);
02881         // used queued for signal-safety
02882         connect(thread, SIGNAL(finished()), SLOT(thread_finished()), Qt::QueuedConnection);
02883         thread->in = in;
02884         thread->start();
02885     }
02886 
02887 private slots:
02888     void thread_finished()
02889     {
02890         out = thread->out;
02891         delete thread;
02892         thread = 0;
02893         active = false;
02894 
02895         emit q->finished();
02896     }
02897 };
02898 
02899 KeyLoader::KeyLoader(QObject *parent)
02900 :QObject(parent)
02901 {
02902     d = new Private(this);
02903 }
02904 
02905 KeyLoader::~KeyLoader()
02906 {
02907     delete d;
02908 }
02909 
02910 void KeyLoader::loadPrivateKeyFromPEMFile(const QString &fileName)
02911 {
02912     Q_ASSERT(!d->active);
02913     if(d->active)
02914         return;
02915 
02916     d->reset();
02917     d->in.type = KeyLoaderThread::PKPEMFile;
02918     d->in.fileName = fileName;
02919     d->start();
02920 }
02921 
02922 void KeyLoader::loadPrivateKeyFromPEM(const QString &s)
02923 {
02924     Q_ASSERT(!d->active);
02925     if(d->active)
02926         return;
02927 
02928     d->reset();
02929     d->in.type = KeyLoaderThread::PKPEM;
02930     d->in.pem = s;
02931     d->start();
02932 }
02933 
02934 void KeyLoader::loadPrivateKeyFromDER(const SecureArray &a)
02935 {
02936     Q_ASSERT(!d->active);
02937     if(d->active)
02938         return;
02939 
02940     d->reset();
02941     d->in.type = KeyLoaderThread::PKDER;
02942     d->in.der = a;
02943     d->start();
02944 }
02945 
02946 void KeyLoader::loadKeyBundleFromFile(const QString &fileName)
02947 {
02948     Q_ASSERT(!d->active);
02949     if(d->active)
02950         return;
02951 
02952     d->reset();
02953     d->in.type = KeyLoaderThread::KBDERFile;
02954     d->in.fileName = fileName;
02955     d->start();
02956 }
02957 
02958 void KeyLoader::loadKeyBundleFromArray(const QByteArray &a)
02959 {
02960     Q_ASSERT(!d->active);
02961     if(d->active)
02962         return;
02963 
02964     d->reset();
02965     d->in.type = KeyLoaderThread::KBDERFile;
02966     d->in.kbder = a;
02967     d->start();
02968 }
02969 
02970 ConvertResult KeyLoader::convertResult() const
02971 {
02972     return d->out.convertResult;
02973 }
02974 
02975 PrivateKey KeyLoader::privateKey() const
02976 {
02977     return d->out.privateKey;
02978 }
02979 
02980 KeyBundle KeyLoader::keyBundle() const
02981 {
02982     return d->out.keyBundle;
02983 }
02984 
02985 }
02986 
02987 #include "qca_cert.moc"

qca

Skip menu "qca"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE Support

Skip menu "KDE Support"
  • akonadi
  • Decibel
  • grantlee
  • kdewin
  • phonon
  •     Backend
  • polkit-qt
  • qca
  • qimageblitz
  • soprano
  • strigi
  •     searchclient
  •     streamanalyzer
  •     streams
Generated for KDE Support by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal