?? qca-ossl.cpp
字號:
/* * Copyright (C) 2004-2007 Justin Karneges <justin@affinix.com> * Copyright (C) 2004-2006 Brad Hards <bradh@frogmouth.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */#include <QtCrypto>#include <qcaprovider.h>#include <QDebug>#include <QtPlugin>#include <openssl/evp.h>#include <openssl/hmac.h>#include <stdio.h>#include <stdlib.h>#include <iostream>#include <openssl/rand.h>#include <openssl/pem.h>#include <openssl/err.h>#include <openssl/x509v3.h>#include <openssl/pkcs12.h>#include <openssl/ssl.h>#ifndef OSSL_097// comment this out if you'd rather use openssl 0.9.6#define OSSL_097#endifusing namespace QCA;namespace opensslQCAPlugin {//----------------------------------------------------------------------------// Util//----------------------------------------------------------------------------static SecureArray bio2buf(BIO *b){ SecureArray buf; while(1) { SecureArray block(1024); int ret = BIO_read(b, block.data(), block.size()); if(ret <= 0) break; block.resize(ret); buf.append(block); if(ret != 1024) break; } BIO_free(b); return buf;}static QByteArray bio2ba(BIO *b){ QByteArray buf; while(1) { QByteArray block(1024, 0); int ret = BIO_read(b, block.data(), block.size()); if(ret <= 0) break; block.resize(ret); buf.append(block); if(ret != 1024) break; } BIO_free(b); return buf;}static BigInteger bn2bi(BIGNUM *n){ SecureArray buf(BN_num_bytes(n) + 1); buf[0] = 0; // positive BN_bn2bin(n, (unsigned char *)buf.data() + 1); return BigInteger(buf);}static BIGNUM *bi2bn(const BigInteger &n){ SecureArray buf = n.toArray(); return BN_bin2bn((const unsigned char *)buf.data(), buf.size(), NULL);}static SecureArray dsasig_der_to_raw(const SecureArray &in){ DSA_SIG *sig = DSA_SIG_new(); const unsigned char *inp = (const unsigned char *)in.data(); d2i_DSA_SIG(&sig, &inp, in.size()); SecureArray part_r(20); SecureArray part_s(20); memset(part_r.data(), 0, 20); memset(part_s.data(), 0, 20); unsigned char *p = (unsigned char *)part_r.data(); BN_bn2bin(sig->r, p); p = (unsigned char *)part_s.data(); BN_bn2bin(sig->s, p); SecureArray result; result.append(part_r); result.append(part_s); DSA_SIG_free(sig); return result;}static SecureArray dsasig_raw_to_der(const SecureArray &in){ if(in.size() != 40) return SecureArray(); DSA_SIG *sig = DSA_SIG_new(); SecureArray part_r(20); SecureArray part_s(20); memcpy(part_r.data(), in.data(), 20); memcpy(part_s.data(), in.data() + 20, 20); sig->r = BN_bin2bn((const unsigned char *)part_r.data(), part_r.size(), NULL); sig->s = BN_bin2bn((const unsigned char *)part_s.data(), part_s.size(), NULL); int len = i2d_DSA_SIG(sig, NULL); SecureArray result(len); unsigned char *p = (unsigned char *)result.data(); i2d_DSA_SIG(sig, &p); DSA_SIG_free(sig); return result;}static int passphrase_cb(char *buf, int size, int rwflag, void *u){ Q_UNUSED(buf); Q_UNUSED(size); Q_UNUSED(rwflag); Q_UNUSED(u); return 0;}/*static bool is_basic_constraint(const ConstraintType &t){ bool basic = false; switch(t.known()) { case DigitalSignature: case NonRepudiation: case KeyEncipherment: case DataEncipherment: case KeyAgreement: case KeyCertificateSign: case CRLSign: case EncipherOnly: case DecipherOnly: basic = true; break; case ServerAuth: case ClientAuth: case CodeSigning: case EmailProtection: case IPSecEndSystem: case IPSecTunnel: case IPSecUser: case TimeStamping: case OCSPSigning: break; } return basic;}static Constraints basic_only(const Constraints &list){ Constraints out; for(int n = 0; n < list.count(); ++n) { if(is_basic_constraint(list[n])) out += list[n]; } return out;}static Constraints ext_only(const Constraints &list){ Constraints out; for(int n = 0; n < list.count(); ++n) { if(!is_basic_constraint(list[n])) out += list[n]; } return out;}*/// logic from Botan/*static Constraints find_constraints(const PKeyContext &key, const Constraints &orig){ Constraints constraints; if(key.key()->type() == PKey::RSA) constraints += KeyEncipherment; if(key.key()->type() == PKey::DH) constraints += KeyAgreement; if(key.key()->type() == PKey::RSA || key.key()->type() == PKey::DSA) { constraints += DigitalSignature; constraints += NonRepudiation; } Constraints limits = basic_only(orig); Constraints the_rest = ext_only(orig); if(!limits.isEmpty()) { Constraints reduced; for(int n = 0; n < constraints.count(); ++n) { if(limits.contains(constraints[n])) reduced += constraints[n]; } constraints = reduced; } constraints += the_rest; return constraints;}*/static void try_add_name_item(X509_NAME **name, int nid, const QString &val){ if(val.isEmpty()) return; QByteArray buf = val.toLatin1(); if(!(*name)) *name = X509_NAME_new(); X509_NAME_add_entry_by_NID(*name, nid, MBSTRING_ASC, (unsigned char *)buf.data(), buf.size(), -1, 0);}static X509_NAME *new_cert_name(const CertificateInfo &info){ X509_NAME *name = 0; // FIXME support multiple items of each type try_add_name_item(&name, NID_commonName, info.value(CommonName)); try_add_name_item(&name, NID_countryName, info.value(Country)); try_add_name_item(&name, NID_localityName, info.value(Locality)); try_add_name_item(&name, NID_stateOrProvinceName, info.value(State)); try_add_name_item(&name, NID_organizationName, info.value(Organization)); try_add_name_item(&name, NID_organizationalUnitName, info.value(OrganizationalUnit)); return name;}static void try_get_name_item(X509_NAME *name, int nid, const CertificateInfoType &t, CertificateInfo *info){ int loc; loc = -1; while ((loc = X509_NAME_get_index_by_NID(name, nid, loc)) != -1) { X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, loc); ASN1_STRING *data = X509_NAME_ENTRY_get_data(ne); QByteArray cs((const char *)data->data, data->length); info->insert(t, QString::fromLatin1(cs)); }}static void try_get_name_item_by_oid(X509_NAME *name, const QString &oidText, const CertificateInfoType &t, CertificateInfo *info){ ASN1_OBJECT *oid = OBJ_txt2obj( oidText.toLatin1().data(), 1); // 1 = only accept dotted input if(!oid) return; int loc; loc = -1; while ((loc = X509_NAME_get_index_by_OBJ(name, oid, loc)) != -1) { X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, loc); ASN1_STRING *data = X509_NAME_ENTRY_get_data(ne); QByteArray cs((const char *)data->data, data->length); info->insert(t, QString::fromLatin1(cs)); qDebug() << "oid: " << oidText << ", result: " << cs; } ASN1_OBJECT_free(oid);}static CertificateInfo get_cert_name(X509_NAME *name){ CertificateInfo info; try_get_name_item(name, NID_commonName, CommonName, &info); try_get_name_item(name, NID_countryName, Country, &info); try_get_name_item_by_oid(name, QString("1.3.6.1.4.1.311.60.2.1.3"), IncorporationCountry, &info); try_get_name_item(name, NID_localityName, Locality, &info); try_get_name_item_by_oid(name, QString("1.3.6.1.4.1.311.60.2.1.1"), IncorporationLocality, &info); try_get_name_item(name, NID_stateOrProvinceName, State, &info); try_get_name_item_by_oid(name, QString("1.3.6.1.4.1.311.60.2.1.2"), IncorporationState, &info); try_get_name_item(name, NID_organizationName, Organization, &info); try_get_name_item(name, NID_organizationalUnitName, OrganizationalUnit, &info); // legacy email { CertificateInfo p9_info; try_get_name_item(name, NID_pkcs9_emailAddress, EmailLegacy, &p9_info); QList<QString> emails = info.values(Email); QMapIterator<CertificateInfoType,QString> it(p9_info); while(it.hasNext()) { it.next(); if(!emails.contains(it.value())) info.insert(Email, it.value()); } } return info;}static X509_EXTENSION *new_subject_key_id(X509 *cert){ X509V3_CTX ctx; X509V3_set_ctx_nodb(&ctx); X509V3_set_ctx(&ctx, NULL, cert, NULL, NULL, 0); X509_EXTENSION *ex = X509V3_EXT_conf_nid(NULL, &ctx, NID_subject_key_identifier, "hash"); return ex;}static X509_EXTENSION *new_basic_constraints(bool ca, int pathlen){ BASIC_CONSTRAINTS *bs = BASIC_CONSTRAINTS_new(); bs->ca = (ca ? 1: 0); bs->pathlen = ASN1_INTEGER_new(); ASN1_INTEGER_set(bs->pathlen, pathlen); X509_EXTENSION *ex = X509V3_EXT_i2d(NID_basic_constraints, 1, bs); // 1 = critical BASIC_CONSTRAINTS_free(bs); return ex;}static void get_basic_constraints(X509_EXTENSION *ex, bool *ca, int *pathlen){ BASIC_CONSTRAINTS *bs = (BASIC_CONSTRAINTS *)X509V3_EXT_d2i(ex); *ca = (bs->ca ? true: false); if(bs->pathlen) *pathlen = ASN1_INTEGER_get(bs->pathlen); else *pathlen = 0; BASIC_CONSTRAINTS_free(bs);}enum ConstraintBit{ Bit_DigitalSignature = 0, Bit_NonRepudiation = 1, Bit_KeyEncipherment = 2, Bit_DataEncipherment = 3, Bit_KeyAgreement = 4, Bit_KeyCertificateSign = 5, Bit_CRLSign = 6, Bit_EncipherOnly = 7, Bit_DecipherOnly = 8};static QByteArray ipaddress_string_to_bytes(const QString &){ return QByteArray(4, 0);}static GENERAL_NAME *new_general_name(const CertificateInfoType &t, const QString &val){ GENERAL_NAME *name = 0; switch(t.known()) { case Email: { QByteArray buf = val.toLatin1(); ASN1_IA5STRING *str = M_ASN1_IA5STRING_new(); ASN1_STRING_set((ASN1_STRING *)str, (unsigned char *)buf.data(), buf.size()); name = GENERAL_NAME_new(); name->type = GEN_EMAIL; name->d.rfc822Name = str; break; } case URI: { QByteArray buf = val.toLatin1(); ASN1_IA5STRING *str = M_ASN1_IA5STRING_new(); ASN1_STRING_set((ASN1_STRING *)str, (unsigned char *)buf.data(), buf.size()); name = GENERAL_NAME_new(); name->type = GEN_URI; name->d.uniformResourceIdentifier = str; break; } case DNS: { QByteArray buf = val.toLatin1(); ASN1_IA5STRING *str = M_ASN1_IA5STRING_new(); ASN1_STRING_set((ASN1_STRING *)str, (unsigned char *)buf.data(), buf.size()); name = GENERAL_NAME_new(); name->type = GEN_DNS; name->d.dNSName = str; break; } case IPAddress: { QByteArray buf = ipaddress_string_to_bytes(val); ASN1_OCTET_STRING *str = ASN1_OCTET_STRING_new(); ASN1_STRING_set((ASN1_STRING *)str, (unsigned char *)buf.data(), buf.size()); name = GENERAL_NAME_new(); name->type = GEN_IPADD; name->d.iPAddress = str; break; } case XMPP: { QByteArray buf = val.toUtf8(); ASN1_UTF8STRING *str = ASN1_UTF8STRING_new(); ASN1_STRING_set((ASN1_STRING *)str, (unsigned char *)buf.data(), buf.size()); ASN1_TYPE *at = ASN1_TYPE_new(); at->type = V_ASN1_UTF8STRING; at->value.utf8string = str; OTHERNAME *other = OTHERNAME_new(); other->type_id = OBJ_txt2obj("1.3.6.1.5.5.7.8.5", 1); // 1 = only accept dotted input other->value = at; name = GENERAL_NAME_new(); name->type = GEN_OTHERNAME; name->d.otherName = other; break; } default: break; } return name;}static void try_add_general_name(GENERAL_NAMES **gn, const CertificateInfoType &t, const QString &val){ if(val.isEmpty()) return; GENERAL_NAME *name = new_general_name(t, val); if(name) { if(!(*gn)) *gn = sk_GENERAL_NAME_new_null(); sk_GENERAL_NAME_push(*gn, name); }}static X509_EXTENSION *new_cert_subject_alt_name(const CertificateInfo &info){ GENERAL_NAMES *gn = 0; // FIXME support multiple items of each type try_add_general_name(&gn, Email, info.value(Email)); try_add_general_name(&gn, URI, info.value(URI)); try_add_general_name(&gn, DNS, info.value(DNS)); try_add_general_name(&gn, IPAddress, info.value(IPAddress)); try_add_general_name(&gn, XMPP, info.value(XMPP)); if(!gn) return 0; X509_EXTENSION *ex = X509V3_EXT_i2d(NID_subject_alt_name, 0, gn); sk_GENERAL_NAME_pop_free(gn, GENERAL_NAME_free); return ex;}static GENERAL_NAME *find_next_general_name(GENERAL_NAMES *names, int type, int *pos){ int temp = *pos; GENERAL_NAME *gn = 0; *pos = -1; for(int n = temp; n < sk_GENERAL_NAME_num(names); ++n) { GENERAL_NAME *i = sk_GENERAL_NAME_value(names, n); if(i->type == type) { gn = i; *pos = n; break; } } return gn;}static void try_get_general_name(GENERAL_NAMES *names, const CertificateInfoType &t, CertificateInfo *info){ switch(t.known()) { case Email: { int pos = 0; while (pos != -1) { GENERAL_NAME *gn = find_next_general_name(names, GEN_EMAIL, &pos); if (pos != -1) { QByteArray cs((const char *)ASN1_STRING_data(gn->d.rfc822Name), ASN1_STRING_length(gn->d.rfc822Name)); info->insert(t, QString::fromLatin1(cs)); ++pos; } } break; } case URI: { int pos = 0; while (pos != -1) { GENERAL_NAME *gn = find_next_general_name(names, GEN_URI, &pos); if (pos != -1) { QByteArray cs((const char *)ASN1_STRING_data(gn->d.uniformResourceIdentifier), ASN1_STRING_length(gn->d.uniformResourceIdentifier)); info->insert(t, QString::fromLatin1(cs)); ++pos; } } break; } case DNS: { int pos = 0; while (pos != -1) { GENERAL_NAME *gn = find_next_general_name(names, GEN_DNS, &pos); if (pos != -1) { QByteArray cs((const char *)ASN1_STRING_data(gn->d.dNSName), ASN1_STRING_length(gn->d.dNSName)); info->insert(t, QString::fromLatin1(cs)); ++pos; } } break; } case IPAddress: { int pos = 0; while (pos != -1) { GENERAL_NAME *gn = find_next_general_name(names, GEN_IPADD, &pos); if (pos != -1) { ASN1_OCTET_STRING *str = gn->d.iPAddress; QByteArray buf((const char *)ASN1_STRING_data(str), ASN1_STRING_length(str)); QString out; // IPv4 (TODO: handle IPv6) if(buf.size() == 4) { out = "0.0.0.0"; } else break; info->insert(t, out); ++pos; } } break; } case XMPP: { int pos = 0; while( pos != -1) { GENERAL_NAME *gn = find_next_general_name(names, GEN_OTHERNAME, &pos); if (pos != -1) { OTHERNAME *other = gn->d.otherName; if(!other) break;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -