2004-11-07 10:08:07 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2004 Justin Karneges
|
2006-01-15 05:41:02 +00:00
|
|
|
* Copyright (C) 2004-2006 Brad Hards <bradh@frogmouth.net>
|
2004-11-07 10:08:07 +00:00
|
|
|
*
|
|
|
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
*/
|
2005-06-25 04:04:29 +00:00
|
|
|
|
2005-02-28 09:56:07 +00:00
|
|
|
#include <QtCore>
|
|
|
|
#include <QtCrypto>
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2004-12-30 08:20:54 +00:00
|
|
|
#include <openssl/evp.h>
|
2004-11-07 10:08:07 +00:00
|
|
|
#include <openssl/hmac.h>
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2005-03-21 07:19:14 +00:00
|
|
|
#include <iostream>
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
#include <openssl/rand.h>
|
|
|
|
#include <openssl/evp.h>
|
|
|
|
#include <openssl/pem.h>
|
|
|
|
#include <openssl/err.h>
|
|
|
|
#include <openssl/x509v3.h>
|
2005-04-09 22:46:24 +00:00
|
|
|
#include <openssl/pkcs12.h>
|
2005-04-22 12:46:55 +00:00
|
|
|
#include <openssl/ssl.h>
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2006-01-15 05:41:02 +00:00
|
|
|
#ifndef OSSL_097
|
2005-03-14 11:38:23 +00:00
|
|
|
// comment this out if you'd rather use openssl 0.9.6
|
2006-01-15 05:41:02 +00:00
|
|
|
#define OSSL_097
|
|
|
|
#endif
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
using namespace QCA;
|
|
|
|
|
2005-03-21 07:19:14 +00:00
|
|
|
namespace opensslQCAPlugin {
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// Util
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
static QSecureArray bio2buf(BIO *b)
|
|
|
|
{
|
|
|
|
QSecureArray buf;
|
|
|
|
while(1) {
|
|
|
|
QSecureArray 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;
|
|
|
|
}
|
|
|
|
|
2005-06-24 23:41:25 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
static QBigInteger bn2bi(BIGNUM *n)
|
|
|
|
{
|
|
|
|
QSecureArray buf(BN_num_bytes(n) + 1);
|
|
|
|
buf[0] = 0; // positive
|
|
|
|
BN_bn2bin(n, (unsigned char *)buf.data() + 1);
|
|
|
|
return QBigInteger(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static BIGNUM *bi2bn(const QBigInteger &n)
|
|
|
|
{
|
|
|
|
QSecureArray buf = n.toArray();
|
|
|
|
return BN_bin2bn((const unsigned char *)buf.data(), buf.size(), NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static QSecureArray dsasig_der_to_raw(const QSecureArray &in)
|
|
|
|
{
|
|
|
|
DSA_SIG *sig = DSA_SIG_new();
|
|
|
|
const unsigned char *inp = (const unsigned char *)in.data();
|
|
|
|
d2i_DSA_SIG(&sig, &inp, in.size());
|
|
|
|
|
|
|
|
QSecureArray part_r(20);
|
|
|
|
QSecureArray 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);
|
|
|
|
QSecureArray result;
|
|
|
|
result.append(part_r);
|
|
|
|
result.append(part_s);
|
|
|
|
|
|
|
|
DSA_SIG_free(sig);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QSecureArray dsasig_raw_to_der(const QSecureArray &in)
|
|
|
|
{
|
|
|
|
if(in.size() != 40)
|
|
|
|
return QSecureArray();
|
|
|
|
|
|
|
|
DSA_SIG *sig = DSA_SIG_new();
|
|
|
|
QSecureArray part_r(20);
|
|
|
|
QSecureArray 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);
|
|
|
|
QSecureArray result(len);
|
|
|
|
unsigned char *p = (unsigned char *)result.data();
|
|
|
|
i2d_DSA_SIG(sig, &p);
|
|
|
|
|
|
|
|
DSA_SIG_free(sig);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static bool is_basic_constraint(ConstraintType t)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
bool basic = false;
|
|
|
|
switch(t)
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
case DigitalSignature:
|
|
|
|
case NonRepudiation:
|
|
|
|
case KeyEncipherment:
|
|
|
|
case DataEncipherment:
|
|
|
|
case KeyAgreement:
|
|
|
|
case KeyCertificateSign:
|
|
|
|
case CRLSign:
|
|
|
|
case EncipherOnly:
|
|
|
|
case DecipherOnly:
|
2005-03-14 11:38:23 +00:00
|
|
|
basic = true;
|
|
|
|
break;
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
case ServerAuth:
|
|
|
|
case ClientAuth:
|
|
|
|
case CodeSigning:
|
|
|
|
case EmailProtection:
|
|
|
|
case IPSecEndSystem:
|
|
|
|
case IPSecTunnel:
|
|
|
|
case IPSecUser:
|
|
|
|
case TimeStamping:
|
|
|
|
case OCSPSigning:
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return basic;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static Constraints basic_only(const Constraints &list)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
Constraints out;
|
2005-03-14 11:38:23 +00:00
|
|
|
for(int n = 0; n < list.count(); ++n)
|
|
|
|
{
|
|
|
|
if(is_basic_constraint(list[n]))
|
|
|
|
out += list[n];
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static Constraints ext_only(const Constraints &list)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
Constraints out;
|
2005-03-14 11:38:23 +00:00
|
|
|
for(int n = 0; n < list.count(); ++n)
|
|
|
|
{
|
|
|
|
if(!is_basic_constraint(list[n]))
|
|
|
|
out += list[n];
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// logic from Botan
|
2005-07-07 00:54:12 +00:00
|
|
|
static Constraints find_constraints(const PKeyContext &key, const Constraints &orig)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
Constraints constraints;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
if(key.key()->type() == PKey::RSA)
|
|
|
|
constraints += KeyEncipherment;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
if(key.key()->type() == PKey::DH)
|
|
|
|
constraints += KeyAgreement;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
if(key.key()->type() == PKey::RSA || key.key()->type() == PKey::DSA)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
constraints += DigitalSignature;
|
|
|
|
constraints += NonRepudiation;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
Constraints limits = basic_only(orig);
|
|
|
|
Constraints the_rest = ext_only(orig);
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
if(!limits.isEmpty())
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
Constraints reduced;
|
2005-03-14 11:38:23 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static X509_NAME *new_cert_name(const CertificateInfo &info)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
X509_NAME *name = 0;
|
2005-07-07 00:54:12 +00:00
|
|
|
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));
|
2005-03-14 11:38:23 +00:00
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static void try_get_name_item(X509_NAME *name, int nid, CertificateInfoType t, CertificateInfo *info)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
int loc = X509_NAME_get_index_by_NID(name, nid, -1);
|
|
|
|
if(loc == -1)
|
|
|
|
return;
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static CertificateInfo get_cert_name(X509_NAME *name)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
CertificateInfo info;
|
|
|
|
try_get_name_item(name, NID_commonName, CommonName, &info);
|
|
|
|
try_get_name_item(name, NID_countryName, Country, &info);
|
|
|
|
try_get_name_item(name, NID_localityName, Locality, &info);
|
|
|
|
try_get_name_item(name, NID_stateOrProvinceName, State, &info);
|
|
|
|
try_get_name_item(name, NID_organizationName, Organization, &info);
|
|
|
|
try_get_name_item(name, NID_organizationalUnitName, OrganizationalUnit, &info);
|
2005-03-14 11:38:23 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static GENERAL_NAME *new_general_name(CertificateInfoType t, const QString &val)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-14 06:51:54 +00:00
|
|
|
GENERAL_NAME *name = 0;
|
2005-03-14 11:38:23 +00:00
|
|
|
switch(t)
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
case Email:
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2005-07-07 00:54:12 +00:00
|
|
|
case URI:
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2005-07-07 00:54:12 +00:00
|
|
|
case DNS:
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2005-07-07 00:54:12 +00:00
|
|
|
case IPAddress:
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2005-07-07 00:54:12 +00:00
|
|
|
case XMPP:
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// the following are not alt_names
|
2005-07-07 00:54:12 +00:00
|
|
|
case CommonName:
|
|
|
|
case Organization:
|
|
|
|
case OrganizationalUnit:
|
|
|
|
case Locality:
|
|
|
|
case State:
|
|
|
|
case Country:
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static void try_add_general_name(GENERAL_NAMES **gn, CertificateInfoType t, const QString &val)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static X509_EXTENSION *new_cert_subject_alt_name(const CertificateInfo &info)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
GENERAL_NAMES *gn = 0;
|
2005-07-07 00:54:12 +00:00
|
|
|
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));
|
2005-03-14 11:38:23 +00:00
|
|
|
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_general_name(GENERAL_NAMES *names, int type)
|
|
|
|
{
|
|
|
|
GENERAL_NAME *gn = 0;
|
|
|
|
for(int n = 0; n < sk_GENERAL_NAME_num(names); ++n)
|
|
|
|
{
|
|
|
|
GENERAL_NAME *i = sk_GENERAL_NAME_value(names, n);
|
|
|
|
if(i->type == type)
|
|
|
|
{
|
|
|
|
gn = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return gn;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static void try_get_general_name(GENERAL_NAMES *names, CertificateInfoType t, CertificateInfo *info)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
switch(t)
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
case Email:
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
GENERAL_NAME *gn = find_general_name(names, GEN_EMAIL);
|
|
|
|
if(!gn)
|
|
|
|
break;
|
|
|
|
QByteArray cs((const char *)ASN1_STRING_data(gn->d.rfc822Name), ASN1_STRING_length(gn->d.rfc822Name));
|
|
|
|
info->insert(t, QString::fromLatin1(cs));
|
|
|
|
break;
|
|
|
|
}
|
2005-07-07 00:54:12 +00:00
|
|
|
case URI:
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
GENERAL_NAME *gn = find_general_name(names, GEN_URI);
|
|
|
|
if(!gn)
|
|
|
|
break;
|
|
|
|
QByteArray cs((const char *)ASN1_STRING_data(gn->d.uniformResourceIdentifier), ASN1_STRING_length(gn->d.uniformResourceIdentifier));
|
|
|
|
info->insert(t, QString::fromLatin1(cs));
|
|
|
|
break;
|
|
|
|
}
|
2005-07-07 00:54:12 +00:00
|
|
|
case DNS:
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
GENERAL_NAME *gn = find_general_name(names, GEN_DNS);
|
|
|
|
if(!gn)
|
|
|
|
break;
|
|
|
|
QByteArray cs((const char *)ASN1_STRING_data(gn->d.dNSName), ASN1_STRING_length(gn->d.dNSName));
|
|
|
|
info->insert(t, QString::fromLatin1(cs));
|
|
|
|
break;
|
|
|
|
}
|
2005-07-07 00:54:12 +00:00
|
|
|
case IPAddress:
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
GENERAL_NAME *gn = find_general_name(names, GEN_IPADD);
|
|
|
|
if(!gn)
|
|
|
|
break;
|
|
|
|
|
|
|
|
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);
|
|
|
|
break;
|
|
|
|
}
|
2005-07-07 00:54:12 +00:00
|
|
|
case XMPP:
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
GENERAL_NAME *gn = find_general_name(names, GEN_OTHERNAME);
|
|
|
|
if(!gn)
|
|
|
|
break;
|
|
|
|
|
|
|
|
OTHERNAME *other = gn->d.otherName;
|
|
|
|
if(!other)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ASN1_OBJECT *obj = OBJ_txt2obj("1.3.6.1.5.5.7.8.5", 1); // 1 = only accept dotted input
|
|
|
|
if(OBJ_cmp(other->type_id, obj) != 0)
|
|
|
|
break;
|
|
|
|
ASN1_OBJECT_free(obj);
|
|
|
|
|
|
|
|
ASN1_TYPE *at = other->value;
|
|
|
|
if(at->type != V_ASN1_UTF8STRING)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ASN1_UTF8STRING *str = at->value.utf8string;
|
|
|
|
QByteArray buf((const char *)ASN1_STRING_data(str), ASN1_STRING_length(str));
|
|
|
|
info->insert(t, QString::fromUtf8(buf));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// the following are not alt_names
|
2005-07-07 00:54:12 +00:00
|
|
|
case CommonName:
|
|
|
|
case Organization:
|
|
|
|
case OrganizationalUnit:
|
|
|
|
case Locality:
|
|
|
|
case State:
|
|
|
|
case Country:
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static CertificateInfo get_cert_subject_alt_name(X509_EXTENSION *ex)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
CertificateInfo info;
|
2005-03-14 11:38:23 +00:00
|
|
|
GENERAL_NAMES *gn = (GENERAL_NAMES *)X509V3_EXT_d2i(ex);
|
2005-07-07 00:54:12 +00:00
|
|
|
try_get_general_name(gn, Email, &info);
|
|
|
|
try_get_general_name(gn, URI, &info);
|
|
|
|
try_get_general_name(gn, DNS, &info);
|
|
|
|
try_get_general_name(gn, IPAddress, &info);
|
|
|
|
try_get_general_name(gn, XMPP, &info);
|
2005-03-14 11:38:23 +00:00
|
|
|
GENERAL_NAMES_free(gn);
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static X509_EXTENSION *new_cert_key_usage(const Constraints &constraints)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
ASN1_BIT_STRING *keyusage = 0;
|
|
|
|
for(int n = 0; n < constraints.count(); ++n)
|
|
|
|
{
|
|
|
|
int bit = -1;
|
|
|
|
switch(constraints[n])
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
case DigitalSignature:
|
2005-03-14 11:38:23 +00:00
|
|
|
bit = Bit_DigitalSignature;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case NonRepudiation:
|
2005-03-14 11:38:23 +00:00
|
|
|
bit = Bit_NonRepudiation;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case KeyEncipherment:
|
2005-03-14 11:38:23 +00:00
|
|
|
bit = Bit_KeyEncipherment;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case DataEncipherment:
|
2005-03-14 11:38:23 +00:00
|
|
|
bit = Bit_DataEncipherment;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case KeyAgreement:
|
2005-03-14 11:38:23 +00:00
|
|
|
bit = Bit_KeyAgreement;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case KeyCertificateSign:
|
2005-03-14 11:38:23 +00:00
|
|
|
bit = Bit_KeyCertificateSign;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case CRLSign:
|
2005-03-14 11:38:23 +00:00
|
|
|
bit = Bit_CRLSign;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case EncipherOnly:
|
2005-03-14 11:38:23 +00:00
|
|
|
bit = Bit_EncipherOnly;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case DecipherOnly:
|
2005-03-14 11:38:23 +00:00
|
|
|
bit = Bit_DecipherOnly;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// the following are not basic key usage
|
2005-07-07 00:54:12 +00:00
|
|
|
case ServerAuth:
|
|
|
|
case ClientAuth:
|
|
|
|
case CodeSigning:
|
|
|
|
case EmailProtection:
|
|
|
|
case IPSecEndSystem:
|
|
|
|
case IPSecTunnel:
|
|
|
|
case IPSecUser:
|
|
|
|
case TimeStamping:
|
|
|
|
case OCSPSigning:
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(bit != -1)
|
|
|
|
{
|
|
|
|
if(!keyusage)
|
|
|
|
keyusage = ASN1_BIT_STRING_new();
|
|
|
|
ASN1_BIT_STRING_set_bit(keyusage, bit, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!keyusage)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
X509_EXTENSION *ex = X509V3_EXT_i2d(NID_key_usage, 1, keyusage); // 1 = critical
|
|
|
|
ASN1_BIT_STRING_free(keyusage);
|
|
|
|
return ex;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static Constraints get_cert_key_usage(X509_EXTENSION *ex)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
Constraints constraints;
|
2005-03-14 11:38:23 +00:00
|
|
|
int bit_table[9] =
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
DigitalSignature,
|
|
|
|
NonRepudiation,
|
|
|
|
KeyEncipherment,
|
|
|
|
DataEncipherment,
|
|
|
|
KeyAgreement,
|
|
|
|
KeyCertificateSign,
|
|
|
|
CRLSign,
|
|
|
|
EncipherOnly,
|
|
|
|
DecipherOnly
|
2005-03-14 11:38:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
ASN1_BIT_STRING *keyusage = (ASN1_BIT_STRING *)X509V3_EXT_d2i(ex);
|
|
|
|
for(int n = 0; n < 9; ++n)
|
|
|
|
{
|
|
|
|
if(ASN1_BIT_STRING_get_bit(keyusage, n))
|
2005-07-07 00:54:12 +00:00
|
|
|
constraints += (ConstraintType)bit_table[n];
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
ASN1_BIT_STRING_free(keyusage);
|
|
|
|
return constraints;
|
|
|
|
};
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static X509_EXTENSION *new_cert_ext_key_usage(const Constraints &constraints)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
EXTENDED_KEY_USAGE *extkeyusage = 0;
|
|
|
|
for(int n = 0; n < constraints.count(); ++n)
|
|
|
|
{
|
|
|
|
int nid = -1;
|
|
|
|
switch(constraints[n])
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
case ServerAuth:
|
2005-03-14 11:38:23 +00:00
|
|
|
nid = NID_server_auth;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case ClientAuth:
|
2005-03-14 11:38:23 +00:00
|
|
|
nid = NID_client_auth;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case CodeSigning:
|
2005-03-14 11:38:23 +00:00
|
|
|
nid = NID_code_sign;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case EmailProtection:
|
2005-03-14 11:38:23 +00:00
|
|
|
nid = NID_email_protect;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case IPSecEndSystem:
|
2005-03-14 11:38:23 +00:00
|
|
|
nid = NID_ipsecEndSystem;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case IPSecTunnel:
|
2005-03-14 11:38:23 +00:00
|
|
|
nid = NID_ipsecTunnel;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case IPSecUser:
|
2005-03-14 11:38:23 +00:00
|
|
|
nid = NID_ipsecUser;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case TimeStamping:
|
2005-03-14 11:38:23 +00:00
|
|
|
nid = NID_time_stamp;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case OCSPSigning:
|
2005-03-14 11:38:23 +00:00
|
|
|
nid = NID_OCSP_sign;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// the following are not extended key usage
|
2005-07-07 00:54:12 +00:00
|
|
|
case DigitalSignature:
|
|
|
|
case NonRepudiation:
|
|
|
|
case KeyEncipherment:
|
|
|
|
case DataEncipherment:
|
|
|
|
case KeyAgreement:
|
|
|
|
case KeyCertificateSign:
|
|
|
|
case CRLSign:
|
|
|
|
case EncipherOnly:
|
|
|
|
case DecipherOnly:
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(nid != -1)
|
|
|
|
{
|
|
|
|
if(!extkeyusage)
|
|
|
|
extkeyusage = sk_ASN1_OBJECT_new_null();
|
|
|
|
ASN1_OBJECT *obj = OBJ_nid2obj(nid);
|
|
|
|
sk_ASN1_OBJECT_push(extkeyusage, obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!extkeyusage)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
X509_EXTENSION *ex = X509V3_EXT_i2d(NID_ext_key_usage, 0, extkeyusage); // 0 = not critical
|
|
|
|
sk_ASN1_OBJECT_pop_free(extkeyusage, ASN1_OBJECT_free);
|
|
|
|
return ex;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static Constraints get_cert_ext_key_usage(X509_EXTENSION *ex)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
Constraints constraints;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
EXTENDED_KEY_USAGE *extkeyusage = (EXTENDED_KEY_USAGE *)X509V3_EXT_d2i(ex);
|
|
|
|
for(int n = 0; n < sk_ASN1_OBJECT_num(extkeyusage); ++n)
|
|
|
|
{
|
|
|
|
ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(extkeyusage, n);
|
|
|
|
int nid = OBJ_obj2nid(obj);
|
|
|
|
if(nid == NID_undef)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
int t = -1;
|
|
|
|
switch(nid)
|
|
|
|
{
|
|
|
|
case NID_server_auth:
|
2005-07-07 00:54:12 +00:00
|
|
|
t = ServerAuth;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case NID_client_auth:
|
2005-07-07 00:54:12 +00:00
|
|
|
t = ClientAuth;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case NID_code_sign:
|
2005-07-07 00:54:12 +00:00
|
|
|
t = CodeSigning;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case NID_email_protect:
|
2005-07-07 00:54:12 +00:00
|
|
|
t = EmailProtection;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case NID_ipsecEndSystem:
|
2005-07-07 00:54:12 +00:00
|
|
|
t = IPSecEndSystem;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case NID_ipsecTunnel:
|
2005-07-07 00:54:12 +00:00
|
|
|
t = IPSecTunnel;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case NID_ipsecUser:
|
2005-07-07 00:54:12 +00:00
|
|
|
t = IPSecUser;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case NID_time_stamp:
|
2005-07-07 00:54:12 +00:00
|
|
|
t = TimeStamping;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case NID_OCSP_sign:
|
2005-07-07 00:54:12 +00:00
|
|
|
t = OCSPSigning;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
|
|
|
if(t == -1)
|
|
|
|
continue;
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
constraints.append((ConstraintType)t);
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
sk_ASN1_OBJECT_pop_free(extkeyusage, ASN1_OBJECT_free);
|
|
|
|
return constraints;
|
|
|
|
};
|
|
|
|
|
|
|
|
static X509_EXTENSION *new_cert_policies(const QStringList &policies)
|
|
|
|
{
|
|
|
|
STACK_OF(POLICYINFO) *pols = 0;
|
|
|
|
for(int n = 0; n < policies.count(); ++n)
|
|
|
|
{
|
|
|
|
QByteArray cs = policies[n].toLatin1();
|
|
|
|
ASN1_OBJECT *obj = OBJ_txt2obj(cs.data(), 1); // 1 = only accept dotted input
|
|
|
|
if(!obj)
|
|
|
|
continue;
|
|
|
|
if(!pols)
|
|
|
|
pols = sk_POLICYINFO_new_null();
|
|
|
|
POLICYINFO *pol = POLICYINFO_new();
|
|
|
|
pol->policyid = obj;
|
|
|
|
sk_POLICYINFO_push(pols, pol);
|
|
|
|
}
|
|
|
|
if(!pols)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
X509_EXTENSION *ex = X509V3_EXT_i2d(NID_certificate_policies, 0, pols); // 0 = not critical
|
|
|
|
sk_POLICYINFO_pop_free(pols, POLICYINFO_free);
|
|
|
|
return ex;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QStringList get_cert_policies(X509_EXTENSION *ex)
|
|
|
|
{
|
|
|
|
QStringList out;
|
|
|
|
STACK_OF(POLICYINFO) *pols = (STACK_OF(POLICYINFO) *)X509V3_EXT_d2i(ex);
|
|
|
|
for(int n = 0; n < sk_POLICYINFO_num(pols); ++n)
|
|
|
|
{
|
|
|
|
POLICYINFO *pol = sk_POLICYINFO_value(pols, n);
|
|
|
|
QByteArray buf(128, 0);
|
|
|
|
OBJ_obj2txt((char *)buf.data(), buf.size(), pol->policyid, 1); // 1 = only accept dotted input
|
|
|
|
out += QString::fromLatin1(buf);
|
|
|
|
}
|
|
|
|
sk_POLICYINFO_pop_free(pols, POLICYINFO_free);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2005-04-05 07:57:40 +00:00
|
|
|
static QByteArray get_cert_subject_key_id(X509_EXTENSION *ex)
|
|
|
|
{
|
|
|
|
ASN1_OCTET_STRING *skid = (ASN1_OCTET_STRING *)X509V3_EXT_d2i(ex);
|
|
|
|
QByteArray out((const char *)ASN1_STRING_data(skid), ASN1_STRING_length(skid));
|
|
|
|
ASN1_OCTET_STRING_free(skid);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2006-02-01 10:59:45 +00:00
|
|
|
// If you get any more crashes in this code, please provide a copy
|
|
|
|
// of the cert to bradh AT frogmouth.net
|
2006-02-01 10:09:29 +00:00
|
|
|
static QByteArray get_cert_issuer_key_id(X509_EXTENSION *ex)
|
2005-04-05 07:57:40 +00:00
|
|
|
{
|
|
|
|
AUTHORITY_KEYID *akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ex);
|
2006-02-01 10:59:45 +00:00
|
|
|
QByteArray out;
|
|
|
|
if (akid->keyid)
|
|
|
|
out = QByteArray((const char *)ASN1_STRING_data(akid->keyid), ASN1_STRING_length(akid->keyid));
|
2005-04-05 07:57:40 +00:00
|
|
|
AUTHORITY_KEYID_free(akid);
|
|
|
|
return out;
|
2006-02-01 10:09:29 +00:00
|
|
|
}
|
2005-04-05 07:57:40 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static Validity convert_verify_error(int err)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
// TODO: ErrorExpiredCA
|
2005-07-07 00:54:12 +00:00
|
|
|
Validity rc;
|
2005-03-14 11:38:23 +00:00
|
|
|
switch(err)
|
|
|
|
{
|
|
|
|
case X509_V_ERR_CERT_REJECTED:
|
2005-07-07 00:54:12 +00:00
|
|
|
rc = ErrorRejected;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case X509_V_ERR_CERT_UNTRUSTED:
|
2005-07-07 00:54:12 +00:00
|
|
|
rc = ErrorUntrusted;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
|
|
|
|
case X509_V_ERR_CERT_SIGNATURE_FAILURE:
|
|
|
|
case X509_V_ERR_CRL_SIGNATURE_FAILURE:
|
|
|
|
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
|
|
|
|
case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
|
2005-07-07 00:54:12 +00:00
|
|
|
rc = ErrorSignatureFailed;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case X509_V_ERR_INVALID_CA:
|
|
|
|
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
|
|
|
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
|
|
|
|
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
2005-07-07 00:54:12 +00:00
|
|
|
rc = ErrorInvalidCA;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case X509_V_ERR_INVALID_PURPOSE: // note: not used by store verify
|
2005-07-07 00:54:12 +00:00
|
|
|
rc = ErrorInvalidPurpose;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
|
|
|
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
2005-07-07 00:54:12 +00:00
|
|
|
rc = ErrorSelfSigned;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case X509_V_ERR_CERT_REVOKED:
|
2005-07-07 00:54:12 +00:00
|
|
|
rc = ErrorRevoked;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case X509_V_ERR_PATH_LENGTH_EXCEEDED:
|
2005-07-07 00:54:12 +00:00
|
|
|
rc = ErrorPathLengthExceeded;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case X509_V_ERR_CERT_NOT_YET_VALID:
|
|
|
|
case X509_V_ERR_CERT_HAS_EXPIRED:
|
|
|
|
case X509_V_ERR_CRL_NOT_YET_VALID:
|
|
|
|
case X509_V_ERR_CRL_HAS_EXPIRED:
|
|
|
|
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
|
|
|
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
|
|
|
case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
|
|
|
|
case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
|
2005-07-07 00:54:12 +00:00
|
|
|
rc = ErrorExpired;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
case X509_V_ERR_APPLICATION_VERIFICATION:
|
|
|
|
case X509_V_ERR_OUT_OF_MEM:
|
|
|
|
case X509_V_ERR_UNABLE_TO_GET_CRL:
|
|
|
|
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
|
|
|
|
default:
|
2005-07-07 00:54:12 +00:00
|
|
|
rc = ErrorValidityUnknown;
|
2005-03-14 11:38:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-09 22:46:24 +00:00
|
|
|
EVP_PKEY *qca_d2i_PKCS8PrivateKey(const QSecureArray &in, EVP_PKEY **x, pem_password_cb *cb, void *u)
|
|
|
|
{
|
|
|
|
PKCS8_PRIV_KEY_INFO *p8inf;
|
|
|
|
|
|
|
|
// first try unencrypted form
|
|
|
|
BIO *bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, in.data(), in.size());
|
|
|
|
p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(bi, NULL);
|
|
|
|
BIO_free(bi);
|
|
|
|
if(!p8inf)
|
|
|
|
{
|
|
|
|
X509_SIG *p8;
|
|
|
|
|
|
|
|
// now try encrypted form
|
|
|
|
bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, in.data(), in.size());
|
|
|
|
p8 = d2i_PKCS8_bio(bi, NULL);
|
|
|
|
BIO_free(bi);
|
|
|
|
if(!p8)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
// get passphrase
|
|
|
|
char psbuf[PEM_BUFSIZE];
|
|
|
|
int klen;
|
|
|
|
if(cb)
|
|
|
|
klen = cb(psbuf, PEM_BUFSIZE, 0, u);
|
|
|
|
else
|
|
|
|
klen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u);
|
|
|
|
if(klen <= 0)
|
|
|
|
{
|
|
|
|
PEMerr(PEM_F_D2I_PKCS8PRIVATEKEY_BIO, PEM_R_BAD_PASSWORD_READ);
|
|
|
|
X509_SIG_free(p8);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// decrypt it
|
|
|
|
p8inf = PKCS8_decrypt(p8, psbuf, klen);
|
|
|
|
X509_SIG_free(p8);
|
|
|
|
if(!p8inf)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EVP_PKEY *ret = EVP_PKCS82PKEY(p8inf);
|
|
|
|
PKCS8_PRIV_KEY_INFO_free(p8inf);
|
|
|
|
if(!ret)
|
|
|
|
return NULL;
|
|
|
|
if(x)
|
|
|
|
{
|
|
|
|
if(*x)
|
|
|
|
EVP_PKEY_free(*x);
|
|
|
|
*x = ret;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
class opensslHashContext : public HashContext
|
2004-11-07 10:08:07 +00:00
|
|
|
{
|
|
|
|
public:
|
2005-07-07 00:54:12 +00:00
|
|
|
opensslHashContext(const EVP_MD *algorithm, Provider *p, const QString &type) : HashContext(p, type)
|
2005-04-03 09:31:00 +00:00
|
|
|
{
|
2006-01-15 05:41:02 +00:00
|
|
|
m_algorithm = algorithm;
|
|
|
|
EVP_DigestInit( &m_context, m_algorithm );
|
2005-04-03 09:31:00 +00:00
|
|
|
};
|
|
|
|
|
2006-01-15 05:41:02 +00:00
|
|
|
~opensslHashContext()
|
|
|
|
{
|
|
|
|
EVP_MD_CTX_cleanup(&m_context);
|
|
|
|
}
|
|
|
|
|
2004-12-30 08:20:54 +00:00
|
|
|
void clear()
|
|
|
|
{
|
2006-01-15 05:41:02 +00:00
|
|
|
EVP_MD_CTX_cleanup(&m_context);
|
2004-12-30 08:20:54 +00:00
|
|
|
EVP_DigestInit( &m_context, m_algorithm );
|
|
|
|
}
|
|
|
|
|
|
|
|
void update(const QSecureArray &a)
|
|
|
|
{
|
|
|
|
EVP_DigestUpdate( &m_context, (unsigned char*)a.data(), a.size() );
|
|
|
|
}
|
|
|
|
|
|
|
|
QSecureArray final()
|
|
|
|
{
|
|
|
|
QSecureArray a( EVP_MD_size( m_algorithm ) );
|
|
|
|
EVP_DigestFinal( &m_context, (unsigned char*)a.data(), 0 );
|
|
|
|
return a;
|
|
|
|
}
|
2005-03-19 09:09:44 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
Provider::Context *clone() const
|
2005-03-19 09:09:44 +00:00
|
|
|
{
|
|
|
|
return new opensslHashContext(*this);
|
|
|
|
}
|
2004-12-30 08:20:54 +00:00
|
|
|
|
2004-11-14 00:27:13 +00:00
|
|
|
protected:
|
2004-12-30 08:20:54 +00:00
|
|
|
const EVP_MD *m_algorithm;
|
|
|
|
EVP_MD_CTX m_context;
|
|
|
|
};
|
2004-11-07 10:08:07 +00:00
|
|
|
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
class opensslPbkdf1Context : public KDFContext
|
2005-04-03 09:31:00 +00:00
|
|
|
{
|
|
|
|
public:
|
2005-07-07 00:54:12 +00:00
|
|
|
opensslPbkdf1Context(const EVP_MD *algorithm, Provider *p, const QString &type) : KDFContext(p, type)
|
2005-04-03 09:31:00 +00:00
|
|
|
{
|
|
|
|
m_algorithm = algorithm;
|
|
|
|
EVP_DigestInit( &m_context, m_algorithm );
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
Provider::Context *clone() const
|
2005-04-03 09:31:00 +00:00
|
|
|
{
|
|
|
|
return new opensslPbkdf1Context( *this );
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
SymmetricKey makeKey(const QSecureArray &secret, const InitializationVector &salt,
|
2005-04-03 09:31:00 +00:00
|
|
|
unsigned int keyLength, unsigned int iterationCount)
|
|
|
|
{
|
|
|
|
/* from RFC2898:
|
|
|
|
Steps:
|
|
|
|
|
|
|
|
1. If dkLen > 16 for MD2 and MD5, or dkLen > 20 for SHA-1, output
|
|
|
|
"derived key too long" and stop.
|
|
|
|
*/
|
|
|
|
if ( keyLength > (unsigned int)EVP_MD_size( m_algorithm ) ) {
|
|
|
|
std::cout << "derived key too long" << std::endl;
|
2005-07-07 00:54:12 +00:00
|
|
|
return SymmetricKey();
|
2005-04-03 09:31:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
2. Apply the underlying hash function Hash for c iterations to the
|
|
|
|
concatenation of the password P and the salt S, then extract
|
|
|
|
the first dkLen octets to produce a derived key DK:
|
|
|
|
|
|
|
|
T_1 = Hash (P || S) ,
|
|
|
|
T_2 = Hash (T_1) ,
|
|
|
|
...
|
|
|
|
T_c = Hash (T_{c-1}) ,
|
|
|
|
DK = Tc<0..dkLen-1>
|
|
|
|
*/
|
|
|
|
// calculate T_1
|
|
|
|
EVP_DigestUpdate( &m_context, (unsigned char*)secret.data(), secret.size() );
|
|
|
|
EVP_DigestUpdate( &m_context, (unsigned char*)salt.data(), salt.size() );
|
|
|
|
QSecureArray a( EVP_MD_size( m_algorithm ) );
|
|
|
|
EVP_DigestFinal( &m_context, (unsigned char*)a.data(), 0 );
|
|
|
|
|
|
|
|
// calculate T_2 up to T_c
|
|
|
|
for ( unsigned int i = 2; i <= iterationCount; ++i ) {
|
|
|
|
EVP_DigestInit( &m_context, m_algorithm );
|
|
|
|
EVP_DigestUpdate( &m_context, (unsigned char*)a.data(), a.size() );
|
|
|
|
EVP_DigestFinal( &m_context, (unsigned char*)a.data(), 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// shrink a to become DK, of the required length
|
|
|
|
a.resize(keyLength);
|
|
|
|
|
|
|
|
/*
|
|
|
|
3. Output the derived key DK.
|
|
|
|
*/
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
const EVP_MD *m_algorithm;
|
|
|
|
EVP_MD_CTX m_context;
|
|
|
|
};
|
2004-11-07 10:08:07 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
class opensslHMACContext : public MACContext
|
2004-12-30 08:20:54 +00:00
|
|
|
{
|
|
|
|
public:
|
2005-07-07 00:54:12 +00:00
|
|
|
opensslHMACContext(const EVP_MD *algorithm, Provider *p, const QString &type) : MACContext(p, type)
|
2005-03-19 07:51:28 +00:00
|
|
|
{
|
|
|
|
m_algorithm = algorithm;
|
|
|
|
HMAC_CTX_init( &m_context );
|
|
|
|
};
|
2004-12-30 08:20:54 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
void setup(const SymmetricKey &key)
|
2004-12-30 08:20:54 +00:00
|
|
|
{
|
|
|
|
HMAC_Init_ex( &m_context, key.data(), key.size(), m_algorithm, 0 );
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
KeyLength keyLength() const
|
2004-12-30 08:20:54 +00:00
|
|
|
{
|
|
|
|
return anyKeyLength();
|
|
|
|
}
|
|
|
|
|
|
|
|
void update(const QSecureArray &a)
|
|
|
|
{
|
|
|
|
HMAC_Update( &m_context, (unsigned char *)a.data(), a.size() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void final( QSecureArray *out)
|
|
|
|
{
|
|
|
|
out->resize( EVP_MD_size( m_algorithm ) );
|
|
|
|
HMAC_Final(&m_context, (unsigned char *)out->data(), 0 );
|
|
|
|
HMAC_CTX_cleanup(&m_context);
|
|
|
|
}
|
2004-11-14 00:27:13 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
Provider::Context *clone() const
|
2004-12-30 08:20:54 +00:00
|
|
|
{
|
2005-03-19 07:51:28 +00:00
|
|
|
return new opensslHMACContext(*this);
|
2004-12-30 08:20:54 +00:00
|
|
|
}
|
|
|
|
|
2005-03-19 07:51:28 +00:00
|
|
|
protected:
|
|
|
|
HMAC_CTX m_context;
|
|
|
|
const EVP_MD *m_algorithm;
|
2004-12-30 08:20:54 +00:00
|
|
|
};
|
2004-11-07 10:08:07 +00:00
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// EVPKey
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// note: this class squelches processing errors, since QCA doesn't care about them
|
|
|
|
class EVPKey
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum State { Idle, SignActive, SignError, VerifyActive, VerifyError };
|
|
|
|
EVP_PKEY *pkey;
|
|
|
|
EVP_MD_CTX mdctx;
|
|
|
|
State state;
|
|
|
|
|
|
|
|
EVPKey()
|
|
|
|
{
|
|
|
|
pkey = 0;
|
|
|
|
state = Idle;
|
|
|
|
}
|
2004-11-07 10:08:07 +00:00
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
EVPKey(const EVPKey &from)
|
|
|
|
{
|
|
|
|
pkey = from.pkey;
|
|
|
|
CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
|
|
|
|
state = Idle;
|
|
|
|
}
|
2004-11-07 10:08:07 +00:00
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
~EVPKey()
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
if(pkey)
|
|
|
|
EVP_PKEY_free(pkey);
|
|
|
|
pkey = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void startSign(const EVP_MD *type)
|
|
|
|
{
|
|
|
|
if(!type)
|
|
|
|
{
|
|
|
|
state = SignError;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
state = SignActive;
|
|
|
|
EVP_MD_CTX_init(&mdctx);
|
|
|
|
if(!EVP_SignInit_ex(&mdctx, type, NULL))
|
|
|
|
state = SignError;
|
|
|
|
}
|
|
|
|
|
|
|
|
void startVerify(const EVP_MD *type)
|
|
|
|
{
|
|
|
|
if(!type)
|
|
|
|
{
|
|
|
|
state = VerifyError;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
state = VerifyActive;
|
|
|
|
EVP_MD_CTX_init(&mdctx);
|
|
|
|
if(!EVP_VerifyInit_ex(&mdctx, type, NULL))
|
|
|
|
state = VerifyError;
|
|
|
|
}
|
|
|
|
|
|
|
|
void update(const QSecureArray &in)
|
|
|
|
{
|
|
|
|
if(state == SignActive)
|
|
|
|
{
|
|
|
|
if(!EVP_SignUpdate(&mdctx, in.data(), (unsigned int)in.size()))
|
|
|
|
state = SignError;
|
|
|
|
}
|
|
|
|
else if(state == VerifyActive)
|
|
|
|
{
|
|
|
|
if(!EVP_VerifyUpdate(&mdctx, in.data(), (unsigned int)in.size()))
|
|
|
|
state = VerifyError;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QSecureArray endSign()
|
|
|
|
{
|
|
|
|
if(state == SignActive)
|
|
|
|
{
|
|
|
|
QSecureArray out(EVP_PKEY_size(pkey));
|
|
|
|
unsigned int len = out.size();
|
|
|
|
if(!EVP_SignFinal(&mdctx, (unsigned char *)out.data(), &len, pkey))
|
|
|
|
{
|
|
|
|
state = SignError;
|
|
|
|
return QSecureArray();
|
|
|
|
}
|
|
|
|
out.resize(len);
|
|
|
|
state = Idle;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return QSecureArray();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool endVerify(const QSecureArray &sig)
|
|
|
|
{
|
|
|
|
if(state == VerifyActive)
|
|
|
|
{
|
|
|
|
if(EVP_VerifyFinal(&mdctx, (unsigned char *)sig.data(), (unsigned int)sig.size(), pkey) != 1)
|
|
|
|
{
|
|
|
|
state = VerifyError;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
state = Idle;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// MyDLGroup
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// IETF primes from Botan
|
|
|
|
const char* IETF_1024_PRIME =
|
|
|
|
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1"
|
|
|
|
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD"
|
|
|
|
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245"
|
|
|
|
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED"
|
|
|
|
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381"
|
|
|
|
"FFFFFFFF FFFFFFFF";
|
|
|
|
|
|
|
|
const char* IETF_2048_PRIME =
|
|
|
|
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1"
|
|
|
|
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD"
|
|
|
|
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245"
|
|
|
|
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED"
|
|
|
|
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D"
|
|
|
|
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F"
|
|
|
|
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D"
|
|
|
|
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B"
|
|
|
|
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9"
|
|
|
|
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510"
|
|
|
|
"15728E5A 8AACAA68 FFFFFFFF FFFFFFFF";
|
|
|
|
|
|
|
|
const char* IETF_4096_PRIME =
|
|
|
|
"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1"
|
|
|
|
"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD"
|
|
|
|
"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245"
|
|
|
|
"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED"
|
|
|
|
"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D"
|
|
|
|
"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F"
|
|
|
|
"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D"
|
|
|
|
"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B"
|
|
|
|
"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9"
|
|
|
|
"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510"
|
|
|
|
"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64"
|
|
|
|
"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7"
|
|
|
|
"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B"
|
|
|
|
"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C"
|
|
|
|
"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31"
|
|
|
|
"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7"
|
|
|
|
"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA"
|
|
|
|
"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6"
|
|
|
|
"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED"
|
|
|
|
"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9"
|
|
|
|
"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199"
|
|
|
|
"FFFFFFFF FFFFFFFF";
|
|
|
|
|
|
|
|
// JCE seeds from Botan
|
|
|
|
const char* JCE_512_SEED = "B869C82B 35D70E1B 1FF91B28 E37A62EC DC34409B";
|
|
|
|
const int JCE_512_COUNTER = 123;
|
|
|
|
|
|
|
|
const char* JCE_768_SEED = "77D0F8C4 DAD15EB8 C4F2F8D6 726CEFD9 6D5BB399";
|
|
|
|
const int JCE_768_COUNTER = 263;
|
|
|
|
|
|
|
|
const char* JCE_1024_SEED = "8D515589 4229D5E6 89EE01E6 018A237E 2CAE64CD";
|
|
|
|
const int JCE_1024_COUNTER = 92;
|
|
|
|
|
|
|
|
static QByteArray dehex(const QString &hex)
|
|
|
|
{
|
|
|
|
QString str;
|
|
|
|
for(int n = 0; n < hex.length(); ++n)
|
|
|
|
{
|
|
|
|
if(hex[n] != ' ')
|
|
|
|
str += hex[n];
|
|
|
|
}
|
2005-07-07 00:54:12 +00:00
|
|
|
return hexToArray(str);
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static QBigInteger decode(const QString &prime)
|
|
|
|
{
|
|
|
|
QByteArray a(1, 0); // 1 byte of zero padding
|
|
|
|
a.append(dehex(prime));
|
|
|
|
return QBigInteger(QSecureArray(a));
|
|
|
|
}
|
|
|
|
|
|
|
|
static QByteArray decode_seed(const QString &hex_seed)
|
|
|
|
{
|
|
|
|
return dehex(hex_seed);
|
|
|
|
}
|
|
|
|
|
|
|
|
class DLParams
|
2004-11-07 10:08:07 +00:00
|
|
|
{
|
|
|
|
public:
|
2005-03-14 11:38:23 +00:00
|
|
|
QBigInteger p, q, g;
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool make_dlgroup(const QByteArray &seed, int bits, int counter, DLParams *params)
|
|
|
|
{
|
|
|
|
int ret_counter;
|
|
|
|
DSA *dsa = DSA_generate_parameters(bits, (unsigned char *)seed.data(), seed.size(), &ret_counter, NULL, NULL, NULL);
|
|
|
|
if(!dsa)
|
|
|
|
return false;
|
|
|
|
if(ret_counter != counter)
|
|
|
|
return false;
|
|
|
|
params->p = bn2bi(dsa->p);
|
|
|
|
params->q = bn2bi(dsa->q);
|
|
|
|
params->g = bn2bi(dsa->g);
|
|
|
|
DSA_free(dsa);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool get_dlgroup(const QBigInteger &p, const QBigInteger &g, DLParams *params)
|
|
|
|
{
|
|
|
|
params->p = p;
|
|
|
|
params->q = QBigInteger(0);
|
|
|
|
params->g = g;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
class DLGroupMaker : public QThread
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
2005-07-07 00:54:12 +00:00
|
|
|
DLGroupSet set;
|
2005-03-14 11:38:23 +00:00
|
|
|
bool ok;
|
|
|
|
DLParams params;
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
DLGroupMaker(DLGroupSet _set)
|
2004-11-07 10:08:07 +00:00
|
|
|
{
|
2005-03-14 11:38:23 +00:00
|
|
|
set = _set;
|
2004-11-07 10:08:07 +00:00
|
|
|
}
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
~DLGroupMaker()
|
2004-11-07 10:08:07 +00:00
|
|
|
{
|
2005-03-14 11:38:23 +00:00
|
|
|
wait();
|
2004-11-07 10:08:07 +00:00
|
|
|
}
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
virtual void run()
|
2004-11-07 10:08:07 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
if(set == DSA_512)
|
2005-03-14 11:38:23 +00:00
|
|
|
ok = make_dlgroup(decode_seed(JCE_512_SEED), 512, JCE_512_COUNTER, ¶ms);
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(set == DSA_768)
|
2005-03-14 11:38:23 +00:00
|
|
|
ok = make_dlgroup(decode_seed(JCE_768_SEED), 768, JCE_768_COUNTER, ¶ms);
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(set == DSA_1024)
|
2005-03-14 11:38:23 +00:00
|
|
|
ok = make_dlgroup(decode_seed(JCE_1024_SEED), 1024, JCE_1024_COUNTER, ¶ms);
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(set == IETF_1024)
|
2005-03-14 11:38:23 +00:00
|
|
|
ok = get_dlgroup(decode(IETF_1024_PRIME), 2, ¶ms);
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(set == IETF_2048)
|
2005-03-14 11:38:23 +00:00
|
|
|
ok = get_dlgroup(decode(IETF_2048_PRIME), 2, ¶ms);
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(set == IETF_4096)
|
2005-03-14 11:38:23 +00:00
|
|
|
ok = get_dlgroup(decode(IETF_4096_PRIME), 2, ¶ms);
|
|
|
|
else
|
|
|
|
ok = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
class MyDLGroup : public DLGroupContext
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
DLGroupMaker *gm;
|
|
|
|
bool wasBlocking;
|
|
|
|
DLParams params;
|
|
|
|
bool empty;
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
MyDLGroup(Provider *p) : DLGroupContext(p)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
gm = 0;
|
|
|
|
empty = true;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
MyDLGroup(const MyDLGroup &from) : DLGroupContext(from.provider())
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
gm = 0;
|
|
|
|
empty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
~MyDLGroup()
|
|
|
|
{
|
|
|
|
delete gm;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider::Context *clone() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
return new MyDLGroup(*this);
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual QList<DLGroupSet> supportedGroupSets() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
QList<DLGroupSet> list;
|
|
|
|
list += DSA_512;
|
|
|
|
list += DSA_768;
|
|
|
|
list += DSA_1024;
|
|
|
|
list += IETF_1024;
|
|
|
|
list += IETF_2048;
|
|
|
|
list += IETF_4096;
|
2005-03-14 11:38:23 +00:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool isNull() const
|
|
|
|
{
|
|
|
|
return empty;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void fetchGroup(DLGroupSet set, bool block)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
params = DLParams();
|
|
|
|
empty = true;
|
|
|
|
|
|
|
|
gm = new DLGroupMaker(set);
|
|
|
|
wasBlocking = block;
|
|
|
|
if(block)
|
|
|
|
{
|
|
|
|
gm->run();
|
|
|
|
gm_finished();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
connect(gm, SIGNAL(finished()), SLOT(gm_finished()));
|
|
|
|
gm->start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void getResult(QBigInteger *p, QBigInteger *q, QBigInteger *g) const
|
|
|
|
{
|
|
|
|
*p = params.p;
|
|
|
|
*q = params.q;
|
|
|
|
*g = params.g;
|
|
|
|
}
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
void gm_finished()
|
|
|
|
{
|
|
|
|
bool ok = gm->ok;
|
|
|
|
if(ok)
|
|
|
|
{
|
|
|
|
params = gm->params;
|
|
|
|
empty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(wasBlocking)
|
|
|
|
delete gm;
|
|
|
|
else
|
|
|
|
gm->deleteLater();
|
|
|
|
gm = 0;
|
|
|
|
|
|
|
|
if(!wasBlocking)
|
|
|
|
emit finished();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// RSAKey
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class RSAKeyMaker : public QThread
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
RSA *result;
|
|
|
|
int bits, exp;
|
|
|
|
|
2005-07-28 12:26:55 +00:00
|
|
|
RSAKeyMaker(int _bits, int _exp, QObject *parent = 0) : QThread(parent), result(0), bits(_bits), exp(_exp)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~RSAKeyMaker()
|
|
|
|
{
|
|
|
|
wait();
|
|
|
|
if(result)
|
|
|
|
RSA_free(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void run()
|
|
|
|
{
|
|
|
|
RSA *rsa = RSA_generate_key(bits, exp, NULL, NULL);
|
|
|
|
if(!rsa)
|
|
|
|
return;
|
|
|
|
result = rsa;
|
|
|
|
}
|
|
|
|
|
|
|
|
RSA *takeResult()
|
|
|
|
{
|
|
|
|
RSA *rsa = result;
|
|
|
|
result = 0;
|
|
|
|
return rsa;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
class RSAKey : public RSAContext
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
EVPKey evp;
|
|
|
|
RSAKeyMaker *keymaker;
|
|
|
|
bool wasBlocking;
|
|
|
|
bool sec;
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
RSAKey(Provider *p) : RSAContext(p)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
keymaker = 0;
|
|
|
|
sec = false;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
RSAKey(const RSAKey &from) : RSAContext(from.provider()), evp(from.evp)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
keymaker = 0;
|
|
|
|
sec = from.sec;
|
|
|
|
}
|
|
|
|
|
|
|
|
~RSAKey()
|
|
|
|
{
|
|
|
|
delete keymaker;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider::Context *clone() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
return new RSAKey(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool isNull() const
|
|
|
|
{
|
|
|
|
return (evp.pkey ? false: true);
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual PKey::Type type() const
|
2005-04-12 10:25:35 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
return PKey::RSA;
|
2005-04-12 10:25:35 +00:00
|
|
|
}
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
virtual bool isPrivate() const
|
|
|
|
{
|
|
|
|
return sec;
|
|
|
|
}
|
|
|
|
|
2005-04-12 10:25:35 +00:00
|
|
|
virtual bool canExport() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
virtual void convertToPublic()
|
|
|
|
{
|
|
|
|
if(!sec)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// extract the public key into DER format
|
|
|
|
int len = i2d_RSAPublicKey(evp.pkey->pkey.rsa, NULL);
|
|
|
|
QSecureArray result(len);
|
|
|
|
unsigned char *p = (unsigned char *)result.data();
|
|
|
|
i2d_RSAPublicKey(evp.pkey->pkey.rsa, &p);
|
|
|
|
p = (unsigned char *)result.data();
|
|
|
|
|
|
|
|
// put the DER public key back into openssl
|
|
|
|
evp.reset();
|
|
|
|
RSA *rsa;
|
|
|
|
#ifdef OSSL_097
|
|
|
|
rsa = d2i_RSAPublicKey(NULL, (const unsigned char **)&p, result.size());
|
|
|
|
#else
|
|
|
|
rsa = d2i_RSAPublicKey(NULL, (unsigned char **)&p, result.size());
|
|
|
|
#endif
|
|
|
|
evp.pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_RSA(evp.pkey, rsa);
|
|
|
|
sec = false;
|
|
|
|
}
|
|
|
|
|
2005-04-04 00:34:13 +00:00
|
|
|
virtual int bits() const
|
|
|
|
{
|
2005-09-11 06:37:26 +00:00
|
|
|
return EVP_PKEY_bits(evp.pkey);
|
2005-04-04 00:34:13 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual int maximumEncryptSize(EncryptionAlgorithm alg) const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
RSA *rsa = evp.pkey->pkey.rsa;
|
2005-07-07 00:54:12 +00:00
|
|
|
if(alg == EME_PKCS1v15)
|
2005-03-14 11:38:23 +00:00
|
|
|
return RSA_size(rsa) - 11 - 1;
|
|
|
|
else // oaep
|
|
|
|
return RSA_size(rsa) - 41 - 1;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual QSecureArray encrypt(const QSecureArray &in, EncryptionAlgorithm alg) const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
RSA *rsa = evp.pkey->pkey.rsa;
|
|
|
|
|
|
|
|
QSecureArray buf = in;
|
|
|
|
int max = maximumEncryptSize(alg);
|
|
|
|
if(buf.size() > max)
|
|
|
|
buf.resize(max);
|
|
|
|
QSecureArray result(RSA_size(rsa));
|
|
|
|
|
|
|
|
int pad;
|
2005-07-07 00:54:12 +00:00
|
|
|
if(alg == EME_PKCS1v15)
|
2005-03-14 11:38:23 +00:00
|
|
|
pad = RSA_PKCS1_PADDING;
|
|
|
|
else // oaep
|
|
|
|
pad = RSA_PKCS1_OAEP_PADDING;
|
|
|
|
|
|
|
|
int ret = RSA_public_encrypt(buf.size(), (unsigned char *)buf.data(), (unsigned char *)result.data(), rsa, pad);
|
|
|
|
if(ret < 0)
|
|
|
|
return QSecureArray();
|
|
|
|
result.resize(ret);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual bool decrypt(const QSecureArray &in, QSecureArray *out, EncryptionAlgorithm alg) const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
RSA *rsa = evp.pkey->pkey.rsa;
|
|
|
|
|
|
|
|
QSecureArray result(RSA_size(rsa));
|
|
|
|
|
|
|
|
int pad;
|
2005-07-07 00:54:12 +00:00
|
|
|
if(alg == EME_PKCS1v15)
|
2005-03-14 11:38:23 +00:00
|
|
|
pad = RSA_PKCS1_PADDING;
|
|
|
|
else // oaep
|
|
|
|
pad = RSA_PKCS1_OAEP_PADDING;
|
|
|
|
|
|
|
|
int ret = RSA_private_decrypt(in.size(), (unsigned char *)in.data(), (unsigned char *)result.data(), rsa, pad);
|
|
|
|
if(ret < 0)
|
|
|
|
return false;
|
|
|
|
result.resize(ret);
|
|
|
|
|
|
|
|
*out = result;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void startSign(SignatureAlgorithm alg, SignatureFormat)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
const EVP_MD *md = 0;
|
2005-07-07 00:54:12 +00:00
|
|
|
if(alg == EMSA3_SHA1)
|
2005-03-14 11:38:23 +00:00
|
|
|
md = EVP_sha1();
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(alg == EMSA3_MD5)
|
2005-03-14 11:38:23 +00:00
|
|
|
md = EVP_md5();
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(alg == EMSA3_MD2)
|
2005-03-14 11:38:23 +00:00
|
|
|
md = EVP_md2();
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(alg == EMSA3_RIPEMD160)
|
2005-03-14 11:38:23 +00:00
|
|
|
md = EVP_ripemd160();
|
2005-07-28 12:26:55 +00:00
|
|
|
else if(alg == EMSA3_Raw)
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
evp.startSign(md);
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void startVerify(SignatureAlgorithm alg, SignatureFormat)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
const EVP_MD *md = 0;
|
2005-07-07 00:54:12 +00:00
|
|
|
if(alg == EMSA3_SHA1)
|
2005-03-14 11:38:23 +00:00
|
|
|
md = EVP_sha1();
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(alg == EMSA3_MD5)
|
2005-03-14 11:38:23 +00:00
|
|
|
md = EVP_md5();
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(alg == EMSA3_MD2)
|
2005-03-14 11:38:23 +00:00
|
|
|
md = EVP_md2();
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(alg == EMSA3_RIPEMD160)
|
2005-03-14 11:38:23 +00:00
|
|
|
md = EVP_ripemd160();
|
2005-07-28 12:26:55 +00:00
|
|
|
else if(alg == EMSA3_Raw)
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
evp.startVerify(md);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void update(const QSecureArray &in)
|
|
|
|
{
|
|
|
|
evp.update(in);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QSecureArray endSign()
|
|
|
|
{
|
|
|
|
return evp.endSign();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool endVerify(const QSecureArray &sig)
|
|
|
|
{
|
|
|
|
return evp.endVerify(sig);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void createPrivate(int bits, int exp, bool block)
|
|
|
|
{
|
|
|
|
evp.reset();
|
|
|
|
|
2006-02-25 02:00:56 +00:00
|
|
|
keymaker = new RSAKeyMaker(bits, exp, !block ? this : 0);
|
2005-03-14 11:38:23 +00:00
|
|
|
wasBlocking = block;
|
|
|
|
if(block)
|
|
|
|
{
|
|
|
|
keymaker->run();
|
|
|
|
km_finished();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
connect(keymaker, SIGNAL(finished()), SLOT(km_finished()));
|
|
|
|
keymaker->start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void createPrivate(const QBigInteger &n, const QBigInteger &e, const QBigInteger &p, const QBigInteger &q, const QBigInteger &d)
|
|
|
|
{
|
|
|
|
evp.reset();
|
|
|
|
|
|
|
|
RSA *rsa = RSA_new();
|
|
|
|
rsa->n = bi2bn(n);
|
|
|
|
rsa->e = bi2bn(e);
|
|
|
|
rsa->p = bi2bn(p);
|
|
|
|
rsa->q = bi2bn(q);
|
|
|
|
rsa->d = bi2bn(d);
|
|
|
|
|
|
|
|
if(!rsa->n || !rsa->e || !rsa->p || !rsa->q || !rsa->d)
|
|
|
|
{
|
|
|
|
RSA_free(rsa);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
evp.pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_RSA(evp.pkey, rsa);
|
|
|
|
sec = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void createPublic(const QBigInteger &n, const QBigInteger &e)
|
|
|
|
{
|
|
|
|
evp.reset();
|
|
|
|
|
|
|
|
RSA *rsa = RSA_new();
|
|
|
|
rsa->n = bi2bn(n);
|
|
|
|
rsa->e = bi2bn(e);
|
|
|
|
|
|
|
|
if(!rsa->n || !rsa->e)
|
|
|
|
{
|
|
|
|
RSA_free(rsa);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
evp.pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_RSA(evp.pkey, rsa);
|
|
|
|
sec = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QBigInteger n() const
|
|
|
|
{
|
|
|
|
return bn2bi(evp.pkey->pkey.rsa->n);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QBigInteger e() const
|
|
|
|
{
|
|
|
|
return bn2bi(evp.pkey->pkey.rsa->e);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QBigInteger p() const
|
|
|
|
{
|
|
|
|
return bn2bi(evp.pkey->pkey.rsa->p);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QBigInteger q() const
|
|
|
|
{
|
|
|
|
return bn2bi(evp.pkey->pkey.rsa->q);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QBigInteger d() const
|
|
|
|
{
|
|
|
|
return bn2bi(evp.pkey->pkey.rsa->d);
|
|
|
|
}
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
void km_finished()
|
|
|
|
{
|
|
|
|
RSA *rsa = keymaker->takeResult();
|
|
|
|
if(wasBlocking)
|
|
|
|
delete keymaker;
|
|
|
|
else
|
|
|
|
keymaker->deleteLater();
|
|
|
|
keymaker = 0;
|
|
|
|
|
|
|
|
if(rsa)
|
|
|
|
{
|
|
|
|
evp.pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_RSA(evp.pkey, rsa);
|
|
|
|
sec = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!wasBlocking)
|
|
|
|
emit finished();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// DSAKey
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class DSAKeyMaker : public QThread
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
2005-07-07 00:54:12 +00:00
|
|
|
DLGroup domain;
|
2005-03-14 11:38:23 +00:00
|
|
|
DSA *result;
|
|
|
|
|
2005-07-28 12:26:55 +00:00
|
|
|
DSAKeyMaker(const DLGroup &_domain, QObject *parent = 0) : QThread(parent), domain(_domain), result(0)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~DSAKeyMaker()
|
|
|
|
{
|
|
|
|
wait();
|
|
|
|
if(result)
|
|
|
|
DSA_free(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void run()
|
|
|
|
{
|
|
|
|
DSA *dsa = DSA_new();
|
|
|
|
dsa->p = bi2bn(domain.p());
|
|
|
|
dsa->q = bi2bn(domain.q());
|
|
|
|
dsa->g = bi2bn(domain.g());
|
|
|
|
if(!DSA_generate_key(dsa))
|
|
|
|
{
|
|
|
|
DSA_free(dsa);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
result = dsa;
|
|
|
|
}
|
|
|
|
|
|
|
|
DSA *takeResult()
|
|
|
|
{
|
|
|
|
DSA *dsa = result;
|
|
|
|
result = 0;
|
|
|
|
return dsa;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// note: DSA doesn't use SignatureAlgorithm, since EMSA1 is always assumed
|
2005-07-07 00:54:12 +00:00
|
|
|
class DSAKey : public DSAContext
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
EVPKey evp;
|
|
|
|
DSAKeyMaker *keymaker;
|
|
|
|
bool wasBlocking;
|
|
|
|
bool transformsig;
|
|
|
|
bool sec;
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
DSAKey(Provider *p) : DSAContext(p)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
keymaker = 0;
|
|
|
|
sec = false;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
DSAKey(const DSAKey &from) : DSAContext(from.provider()), evp(from.evp)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
keymaker = 0;
|
|
|
|
sec = from.sec;
|
|
|
|
}
|
|
|
|
|
|
|
|
~DSAKey()
|
|
|
|
{
|
|
|
|
delete keymaker;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider::Context *clone() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
return new DSAKey(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool isNull() const
|
|
|
|
{
|
|
|
|
return (evp.pkey ? false: true);
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual PKey::Type type() const
|
2005-04-12 10:25:35 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
return PKey::DSA;
|
2005-04-12 10:25:35 +00:00
|
|
|
}
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
virtual bool isPrivate() const
|
|
|
|
{
|
|
|
|
return sec;
|
|
|
|
}
|
|
|
|
|
2005-04-12 10:25:35 +00:00
|
|
|
virtual bool canExport() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
virtual void convertToPublic()
|
|
|
|
{
|
|
|
|
if(!sec)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// extract the public key into DER format
|
|
|
|
int len = i2d_DSAPublicKey(evp.pkey->pkey.dsa, NULL);
|
|
|
|
QSecureArray result(len);
|
|
|
|
unsigned char *p = (unsigned char *)result.data();
|
|
|
|
i2d_DSAPublicKey(evp.pkey->pkey.dsa, &p);
|
|
|
|
p = (unsigned char *)result.data();
|
|
|
|
|
|
|
|
// put the DER public key back into openssl
|
|
|
|
evp.reset();
|
|
|
|
DSA *dsa;
|
|
|
|
#ifdef OSSL_097
|
|
|
|
dsa = d2i_DSAPublicKey(NULL, (const unsigned char **)&p, result.size());
|
|
|
|
#else
|
|
|
|
dsa = d2i_DSAPublicKey(NULL, (unsigned char **)&p, result.size());
|
|
|
|
#endif
|
|
|
|
evp.pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_DSA(evp.pkey, dsa);
|
|
|
|
sec = false;
|
|
|
|
}
|
|
|
|
|
2005-04-04 00:34:13 +00:00
|
|
|
virtual int bits() const
|
|
|
|
{
|
2005-09-11 06:37:26 +00:00
|
|
|
return EVP_PKEY_bits(evp.pkey);
|
2005-04-04 00:34:13 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void startSign(SignatureAlgorithm, SignatureFormat format)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
// openssl native format is DER, so transform otherwise
|
2005-07-07 00:54:12 +00:00
|
|
|
if(format != DERSequence)
|
2005-03-14 11:38:23 +00:00
|
|
|
transformsig = true;
|
|
|
|
else
|
|
|
|
transformsig = false;
|
|
|
|
|
|
|
|
evp.startSign(EVP_dss1());
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void startVerify(SignatureAlgorithm, SignatureFormat format)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
// openssl native format is DER, so transform otherwise
|
2005-07-07 00:54:12 +00:00
|
|
|
if(format != DERSequence)
|
2005-03-14 11:38:23 +00:00
|
|
|
transformsig = true;
|
|
|
|
else
|
|
|
|
transformsig = false;
|
|
|
|
|
|
|
|
evp.startVerify(EVP_dss1());
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void update(const QSecureArray &in)
|
|
|
|
{
|
|
|
|
evp.update(in);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QSecureArray endSign()
|
|
|
|
{
|
|
|
|
QSecureArray out = evp.endSign();
|
|
|
|
if(transformsig)
|
|
|
|
return dsasig_der_to_raw(out);
|
|
|
|
else
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool endVerify(const QSecureArray &sig)
|
|
|
|
{
|
|
|
|
QSecureArray in;
|
|
|
|
if(transformsig)
|
|
|
|
in = dsasig_raw_to_der(sig);
|
|
|
|
else
|
|
|
|
in = sig;
|
|
|
|
return evp.endVerify(in);
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void createPrivate(const DLGroup &domain, bool block)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
evp.reset();
|
|
|
|
|
2006-02-25 02:00:56 +00:00
|
|
|
keymaker = new DSAKeyMaker(domain, !block ? this : 0);
|
2005-03-14 11:38:23 +00:00
|
|
|
wasBlocking = block;
|
|
|
|
if(block)
|
|
|
|
{
|
|
|
|
keymaker->run();
|
|
|
|
km_finished();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
connect(keymaker, SIGNAL(finished()), SLOT(km_finished()));
|
|
|
|
keymaker->start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void createPrivate(const DLGroup &domain, const QBigInteger &y, const QBigInteger &x)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
evp.reset();
|
|
|
|
|
|
|
|
DSA *dsa = DSA_new();
|
|
|
|
dsa->p = bi2bn(domain.p());
|
|
|
|
dsa->q = bi2bn(domain.q());
|
|
|
|
dsa->g = bi2bn(domain.g());
|
|
|
|
dsa->pub_key = bi2bn(y);
|
|
|
|
dsa->priv_key = bi2bn(x);
|
|
|
|
|
|
|
|
if(!dsa->p || !dsa->q || !dsa->g || !dsa->pub_key || !dsa->priv_key)
|
|
|
|
{
|
|
|
|
DSA_free(dsa);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
evp.pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_DSA(evp.pkey, dsa);
|
|
|
|
sec = true;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void createPublic(const DLGroup &domain, const QBigInteger &y)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
evp.reset();
|
|
|
|
|
|
|
|
DSA *dsa = DSA_new();
|
|
|
|
dsa->p = bi2bn(domain.p());
|
|
|
|
dsa->q = bi2bn(domain.q());
|
|
|
|
dsa->g = bi2bn(domain.g());
|
|
|
|
dsa->pub_key = bi2bn(y);
|
|
|
|
|
|
|
|
if(!dsa->p || !dsa->q || !dsa->g || !dsa->pub_key)
|
|
|
|
{
|
|
|
|
DSA_free(dsa);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
evp.pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_DSA(evp.pkey, dsa);
|
|
|
|
sec = false;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual DLGroup domain() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
return DLGroup(bn2bi(evp.pkey->pkey.dsa->p), bn2bi(evp.pkey->pkey.dsa->q), bn2bi(evp.pkey->pkey.dsa->g));
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual QBigInteger y() const
|
|
|
|
{
|
|
|
|
return bn2bi(evp.pkey->pkey.dsa->pub_key);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QBigInteger x() const
|
|
|
|
{
|
|
|
|
return bn2bi(evp.pkey->pkey.dsa->priv_key);
|
|
|
|
}
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
void km_finished()
|
|
|
|
{
|
|
|
|
DSA *dsa = keymaker->takeResult();
|
|
|
|
if(wasBlocking)
|
|
|
|
delete keymaker;
|
|
|
|
else
|
|
|
|
keymaker->deleteLater();
|
|
|
|
keymaker = 0;
|
|
|
|
|
|
|
|
if(dsa)
|
|
|
|
{
|
|
|
|
evp.pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_DSA(evp.pkey, dsa);
|
|
|
|
sec = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!wasBlocking)
|
|
|
|
emit finished();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// DHKey
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class DHKeyMaker : public QThread
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
2005-07-07 00:54:12 +00:00
|
|
|
DLGroup domain;
|
2005-03-14 11:38:23 +00:00
|
|
|
DH *result;
|
|
|
|
|
2005-07-28 12:26:55 +00:00
|
|
|
DHKeyMaker(const DLGroup &_domain, QObject *parent = 0) : QThread(parent), domain(_domain), result(0)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~DHKeyMaker()
|
|
|
|
{
|
|
|
|
wait();
|
|
|
|
if(result)
|
|
|
|
DH_free(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void run()
|
|
|
|
{
|
|
|
|
DH *dh = DH_new();
|
|
|
|
dh->p = bi2bn(domain.p());
|
|
|
|
dh->g = bi2bn(domain.g());
|
|
|
|
if(!DH_generate_key(dh))
|
|
|
|
{
|
|
|
|
DH_free(dh);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
result = dh;
|
|
|
|
}
|
|
|
|
|
|
|
|
DH *takeResult()
|
|
|
|
{
|
|
|
|
DH *dh = result;
|
|
|
|
result = 0;
|
|
|
|
return dh;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
class DHKey : public DHContext
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
EVPKey evp;
|
|
|
|
DHKeyMaker *keymaker;
|
|
|
|
bool wasBlocking;
|
|
|
|
bool sec;
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
DHKey(Provider *p) : DHContext(p)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
keymaker = 0;
|
|
|
|
sec = false;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
DHKey(const DHKey &from) : DHContext(from.provider()), evp(from.evp)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
keymaker = 0;
|
|
|
|
sec = from.sec;
|
|
|
|
}
|
|
|
|
|
|
|
|
~DHKey()
|
|
|
|
{
|
|
|
|
delete keymaker;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider::Context *clone() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
return new DHKey(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool isNull() const
|
|
|
|
{
|
|
|
|
return (evp.pkey ? false: true);
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual PKey::Type type() const
|
2005-04-12 10:25:35 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
return PKey::DH;
|
2005-04-12 10:25:35 +00:00
|
|
|
}
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
virtual bool isPrivate() const
|
|
|
|
{
|
|
|
|
return sec;
|
|
|
|
}
|
|
|
|
|
2005-04-12 10:25:35 +00:00
|
|
|
virtual bool canExport() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
virtual void convertToPublic()
|
|
|
|
{
|
|
|
|
if(!sec)
|
|
|
|
return;
|
|
|
|
|
|
|
|
DH *orig = evp.pkey->pkey.dh;
|
|
|
|
DH *dh = DH_new();
|
|
|
|
dh->p = BN_dup(orig->p);
|
|
|
|
dh->g = BN_dup(orig->g);
|
|
|
|
dh->pub_key = BN_dup(orig->pub_key);
|
|
|
|
|
|
|
|
evp.reset();
|
|
|
|
|
|
|
|
evp.pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_DH(evp.pkey, dh);
|
|
|
|
sec = false;
|
|
|
|
}
|
|
|
|
|
2005-04-04 00:34:13 +00:00
|
|
|
virtual int bits() const
|
|
|
|
{
|
2005-09-11 06:37:26 +00:00
|
|
|
return EVP_PKEY_bits(evp.pkey);
|
2005-04-04 00:34:13 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual SymmetricKey deriveKey(const PKeyBase &theirs) const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
DH *dh = evp.pkey->pkey.dh;
|
|
|
|
DH *them = static_cast<const DHKey *>(&theirs)->evp.pkey->pkey.dh;
|
|
|
|
QSecureArray result(DH_size(dh));
|
|
|
|
int ret = DH_compute_key((unsigned char *)result.data(), them->pub_key, dh);
|
|
|
|
if(ret <= 0)
|
2005-07-07 00:54:12 +00:00
|
|
|
return SymmetricKey();
|
2005-03-14 11:38:23 +00:00
|
|
|
result.resize(ret);
|
2005-07-07 00:54:12 +00:00
|
|
|
return SymmetricKey(result);
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void createPrivate(const DLGroup &domain, bool block)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
evp.reset();
|
|
|
|
|
2006-02-25 02:00:56 +00:00
|
|
|
keymaker = new DHKeyMaker(domain, !block ? this : 0);
|
2005-03-14 11:38:23 +00:00
|
|
|
wasBlocking = block;
|
|
|
|
if(block)
|
|
|
|
{
|
|
|
|
keymaker->run();
|
|
|
|
km_finished();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
connect(keymaker, SIGNAL(finished()), SLOT(km_finished()));
|
|
|
|
keymaker->start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void createPrivate(const DLGroup &domain, const QBigInteger &y, const QBigInteger &x)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
evp.reset();
|
|
|
|
|
|
|
|
DH *dh = DH_new();
|
|
|
|
dh->p = bi2bn(domain.p());
|
|
|
|
dh->g = bi2bn(domain.g());
|
|
|
|
dh->pub_key = bi2bn(y);
|
|
|
|
dh->priv_key = bi2bn(x);
|
|
|
|
|
|
|
|
if(!dh->p || !dh->g || !dh->pub_key || !dh->priv_key)
|
|
|
|
{
|
|
|
|
DH_free(dh);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
evp.pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_DH(evp.pkey, dh);
|
|
|
|
sec = true;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void createPublic(const DLGroup &domain, const QBigInteger &y)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
evp.reset();
|
|
|
|
|
|
|
|
DH *dh = DH_new();
|
|
|
|
dh->p = bi2bn(domain.p());
|
|
|
|
dh->g = bi2bn(domain.g());
|
|
|
|
dh->pub_key = bi2bn(y);
|
|
|
|
|
|
|
|
if(!dh->p || !dh->g || !dh->pub_key)
|
|
|
|
{
|
|
|
|
DH_free(dh);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
evp.pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_DH(evp.pkey, dh);
|
|
|
|
sec = false;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual DLGroup domain() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
return DLGroup(bn2bi(evp.pkey->pkey.dh->p), bn2bi(evp.pkey->pkey.dh->g));
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual QBigInteger y() const
|
|
|
|
{
|
|
|
|
return bn2bi(evp.pkey->pkey.dh->pub_key);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QBigInteger x() const
|
|
|
|
{
|
|
|
|
return bn2bi(evp.pkey->pkey.dh->priv_key);
|
|
|
|
}
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
void km_finished()
|
|
|
|
{
|
|
|
|
DH *dh = keymaker->takeResult();
|
|
|
|
if(wasBlocking)
|
|
|
|
delete keymaker;
|
|
|
|
else
|
|
|
|
keymaker->deleteLater();
|
|
|
|
keymaker = 0;
|
|
|
|
|
|
|
|
if(dh)
|
|
|
|
{
|
|
|
|
evp.pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_DH(evp.pkey, dh);
|
|
|
|
sec = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!wasBlocking)
|
|
|
|
emit finished();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-07-28 12:26:55 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// QCA-based RSA_METHOD
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// only supports EMSA3_Raw for now
|
|
|
|
class QCA_RSA_METHOD
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
RSAPrivateKey key;
|
|
|
|
|
|
|
|
QCA_RSA_METHOD(RSAPrivateKey _key, RSA *rsa)
|
|
|
|
{
|
|
|
|
key = _key;
|
|
|
|
RSA_set_method(rsa, rsa_method());
|
|
|
|
rsa->flags |= RSA_FLAG_SIGN_VER;
|
|
|
|
RSA_set_app_data(rsa, this);
|
|
|
|
rsa->n = bi2bn(_key.n());
|
|
|
|
rsa->e = bi2bn(_key.e());
|
|
|
|
}
|
|
|
|
|
|
|
|
RSA_METHOD *rsa_method()
|
|
|
|
{
|
|
|
|
static RSA_METHOD *ops = 0;
|
|
|
|
|
|
|
|
if(!ops)
|
|
|
|
{
|
|
|
|
ops = new RSA_METHOD(*RSA_get_default_method());
|
|
|
|
ops->rsa_priv_enc = 0;//pkcs11_rsa_encrypt;
|
|
|
|
ops->rsa_priv_dec = 0;//pkcs11_rsa_decrypt;
|
|
|
|
ops->rsa_sign = rsa_sign;
|
|
|
|
ops->rsa_verify = 0;//pkcs11_rsa_verify;
|
|
|
|
ops->finish = rsa_finish;
|
|
|
|
}
|
|
|
|
return ops;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rsa_sign(int type, const unsigned char *m, unsigned int m_len, unsigned char *sigret, unsigned int *siglen, const RSA *rsa)
|
|
|
|
{
|
|
|
|
QCA_RSA_METHOD *self = (QCA_RSA_METHOD *)RSA_get_app_data(rsa);
|
|
|
|
|
|
|
|
// TODO: this is disgusting
|
|
|
|
|
|
|
|
unsigned char *p, *tmps = NULL;
|
|
|
|
const unsigned char *s = NULL;
|
|
|
|
int i,j;//,ret=1;
|
|
|
|
|
|
|
|
if(type == NID_md5_sha1)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
// make X509 packet
|
|
|
|
X509_SIG sig;
|
|
|
|
ASN1_TYPE parameter;
|
|
|
|
|
|
|
|
X509_ALGOR algor;
|
|
|
|
ASN1_OCTET_STRING digest;
|
|
|
|
int rsa_size = RSA_size(rsa);
|
|
|
|
//int rsa_size = 128;
|
|
|
|
//CK_ULONG sigsize = rsa_size;
|
|
|
|
|
|
|
|
sig.algor= &algor;
|
|
|
|
sig.algor->algorithm=OBJ_nid2obj(type);
|
|
|
|
if (sig.algor->algorithm == NULL)
|
|
|
|
{
|
|
|
|
//RSAerr(RSA_F_RSA_SIGN,RSA_R_UNKNOWN_ALGORITHM_TYPE);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (sig.algor->algorithm->length == 0)
|
|
|
|
{
|
|
|
|
//RSAerr(RSA_F_RSA_SIGN,RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
parameter.type=V_ASN1_NULL;
|
|
|
|
parameter.value.ptr=NULL;
|
|
|
|
sig.algor->parameter= ¶meter;
|
|
|
|
|
|
|
|
sig.digest= &digest;
|
|
|
|
sig.digest->data=(unsigned char *)m; /* TMP UGLY CAST */
|
|
|
|
sig.digest->length=m_len;
|
|
|
|
|
|
|
|
i=i2d_X509_SIG(&sig,NULL);
|
|
|
|
|
|
|
|
j=rsa_size;
|
|
|
|
if (i > (j-RSA_PKCS1_PADDING_SIZE))
|
|
|
|
{
|
|
|
|
//RSAerr(RSA_F_RSA_SIGN,RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmps=(unsigned char *)OPENSSL_malloc((unsigned int)j+1);
|
|
|
|
if (tmps == NULL)
|
|
|
|
{
|
|
|
|
//RSAerr(RSA_F_RSA_SIGN,ERR_R_MALLOC_FAILURE);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
p=tmps;
|
|
|
|
i2d_X509_SIG(&sig,&p);
|
|
|
|
s=tmps;
|
|
|
|
m = s;
|
|
|
|
m_len = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
QSecureArray input;
|
|
|
|
input.resize(m_len);
|
|
|
|
memcpy(input.data(), m, input.size());
|
|
|
|
QSecureArray result = self->key.signMessage(input, EMSA3_Raw);
|
|
|
|
|
|
|
|
if(tmps)
|
|
|
|
{
|
|
|
|
OPENSSL_cleanse(tmps,(unsigned int)j+1);
|
|
|
|
OPENSSL_free(tmps);
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(sigret, result.data(), result.size());
|
|
|
|
*siglen = result.size();
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rsa_finish(RSA *rsa)
|
|
|
|
{
|
|
|
|
QCA_RSA_METHOD *self = (QCA_RSA_METHOD *)RSA_get_app_data(rsa);
|
|
|
|
delete self;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static RSA *createFromExisting(const RSAPrivateKey &key)
|
|
|
|
{
|
|
|
|
RSA *r = RSA_new();
|
|
|
|
new QCA_RSA_METHOD(key, r); // will delete itself on RSA_free
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// MyPKeyContext
|
|
|
|
//----------------------------------------------------------------------------
|
2005-07-07 00:54:12 +00:00
|
|
|
class MyPKeyContext : public PKeyContext
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
public:
|
2005-07-07 00:54:12 +00:00
|
|
|
PKeyBase *k;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
MyPKeyContext(Provider *p) : PKeyContext(p)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
k = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
~MyPKeyContext()
|
|
|
|
{
|
|
|
|
delete k;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider::Context *clone() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
MyPKeyContext *c = new MyPKeyContext(*this);
|
2005-07-07 00:54:12 +00:00
|
|
|
c->k = (PKeyBase *)k->clone();
|
2005-03-14 11:38:23 +00:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual QList<PKey::Type> supportedTypes() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
QList<PKey::Type> list;
|
|
|
|
list += PKey::RSA;
|
|
|
|
list += PKey::DSA;
|
|
|
|
list += PKey::DH;
|
2005-03-14 11:38:23 +00:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual QList<PKey::Type> supportedIOTypes() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
QList<PKey::Type> list;
|
|
|
|
list += PKey::RSA;
|
|
|
|
list += PKey::DSA;
|
2005-03-14 11:38:23 +00:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual QList<PBEAlgorithm> supportedPBEAlgorithms() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
QList<PBEAlgorithm> list;
|
|
|
|
list += PBES2_DES_SHA1;
|
|
|
|
list += PBES2_TripleDES_SHA1;
|
2005-03-14 11:38:23 +00:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual PKeyBase *key()
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
return k;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual const PKeyBase *key() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
return k;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void setKey(PKeyBase *key)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-12 10:25:35 +00:00
|
|
|
k = key;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual bool importKey(const PKeyBase *key)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-12 10:25:35 +00:00
|
|
|
Q_UNUSED(key);
|
|
|
|
return false;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EVP_PKEY *get_pkey() const
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
PKey::Type t = k->type();
|
|
|
|
if(t == PKey::RSA)
|
2005-03-14 11:38:23 +00:00
|
|
|
return static_cast<RSAKey *>(k)->evp.pkey;
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(t == PKey::DSA)
|
2005-03-14 11:38:23 +00:00
|
|
|
return static_cast<DSAKey *>(k)->evp.pkey;
|
|
|
|
else
|
|
|
|
return static_cast<DHKey *>(k)->evp.pkey;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
PKeyBase *pkeyToBase(EVP_PKEY *pkey, bool sec) const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
PKeyBase *nk = 0;
|
2005-03-14 11:38:23 +00:00
|
|
|
if(pkey->type == EVP_PKEY_RSA)
|
|
|
|
{
|
|
|
|
RSAKey *c = new RSAKey(provider());
|
|
|
|
c->evp.pkey = pkey;
|
|
|
|
c->sec = sec;
|
|
|
|
nk = c;
|
|
|
|
}
|
|
|
|
else if(pkey->type == EVP_PKEY_DSA)
|
|
|
|
{
|
|
|
|
DSAKey *c = new DSAKey(provider());
|
|
|
|
c->evp.pkey = pkey;
|
|
|
|
c->sec = sec;
|
|
|
|
nk = c;
|
|
|
|
}
|
|
|
|
else if(pkey->type == EVP_PKEY_DH)
|
|
|
|
{
|
|
|
|
DHKey *c = new DHKey(provider());
|
|
|
|
c->evp.pkey = pkey;
|
|
|
|
c->sec = sec;
|
|
|
|
nk = c;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
EVP_PKEY_free(pkey);
|
|
|
|
}
|
|
|
|
return nk;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QSecureArray publicToDER() const
|
|
|
|
{
|
|
|
|
EVP_PKEY *pkey = get_pkey();
|
|
|
|
|
|
|
|
// OpenSSL does not have DH import/export support
|
|
|
|
if(pkey->type == EVP_PKEY_DH)
|
|
|
|
return QSecureArray();
|
|
|
|
|
|
|
|
BIO *bo = BIO_new(BIO_s_mem());
|
|
|
|
i2d_PUBKEY_bio(bo, pkey);
|
|
|
|
QSecureArray buf = bio2buf(bo);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QString publicToPEM() const
|
|
|
|
{
|
|
|
|
EVP_PKEY *pkey = get_pkey();
|
|
|
|
|
|
|
|
// OpenSSL does not have DH import/export support
|
|
|
|
if(pkey->type == EVP_PKEY_DH)
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
BIO *bo = BIO_new(BIO_s_mem());
|
|
|
|
PEM_write_bio_PUBKEY(bo, pkey);
|
|
|
|
QSecureArray buf = bio2buf(bo);
|
|
|
|
return QString::fromLatin1(buf.toByteArray());
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual ConvertResult publicFromDER(const QSecureArray &in)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
delete k;
|
|
|
|
k = 0;
|
|
|
|
|
|
|
|
BIO *bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, in.data(), in.size());
|
|
|
|
EVP_PKEY *pkey = d2i_PUBKEY_bio(bi, NULL);
|
|
|
|
BIO_free(bi);
|
|
|
|
|
|
|
|
if(!pkey)
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
k = pkeyToBase(pkey, false);
|
|
|
|
if(k)
|
2005-07-07 00:54:12 +00:00
|
|
|
return ConvertGood;
|
2005-03-14 11:38:23 +00:00
|
|
|
else
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual ConvertResult publicFromPEM(const QString &s)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
delete k;
|
|
|
|
k = 0;
|
|
|
|
|
|
|
|
QByteArray in = s.toLatin1();
|
|
|
|
BIO *bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, in.data(), in.size());
|
|
|
|
EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bi, NULL, NULL, NULL);
|
|
|
|
BIO_free(bi);
|
|
|
|
|
|
|
|
if(!pkey)
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
k = pkeyToBase(pkey, false);
|
|
|
|
if(k)
|
2005-07-07 00:54:12 +00:00
|
|
|
return ConvertGood;
|
2005-03-14 11:38:23 +00:00
|
|
|
else
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual QSecureArray privateToDER(const QSecureArray &passphrase, PBEAlgorithm pbe) const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
//if(pbe == PBEDefault)
|
|
|
|
// pbe = PBES2_TripleDES_SHA1;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
const EVP_CIPHER *cipher = 0;
|
2005-07-07 00:54:12 +00:00
|
|
|
if(pbe == PBES2_TripleDES_SHA1)
|
2005-03-14 11:38:23 +00:00
|
|
|
cipher = EVP_des_ede3_cbc();
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(pbe == PBES2_DES_SHA1)
|
2005-03-14 11:38:23 +00:00
|
|
|
cipher = EVP_des_cbc();
|
|
|
|
|
|
|
|
if(!cipher)
|
|
|
|
return QSecureArray();
|
|
|
|
|
|
|
|
EVP_PKEY *pkey = get_pkey();
|
|
|
|
|
|
|
|
// OpenSSL does not have DH import/export support
|
|
|
|
if(pkey->type == EVP_PKEY_DH)
|
|
|
|
return QSecureArray();
|
|
|
|
|
|
|
|
BIO *bo = BIO_new(BIO_s_mem());
|
|
|
|
if(!passphrase.isEmpty())
|
|
|
|
i2d_PKCS8PrivateKey_bio(bo, pkey, cipher, NULL, 0, NULL, (void *)passphrase.data());
|
|
|
|
else
|
|
|
|
i2d_PKCS8PrivateKey_bio(bo, pkey, NULL, NULL, 0, NULL, NULL);
|
|
|
|
QSecureArray buf = bio2buf(bo);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual QString privateToPEM(const QSecureArray &passphrase, PBEAlgorithm pbe) const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
//if(pbe == PBEDefault)
|
|
|
|
// pbe = PBES2_TripleDES_SHA1;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
const EVP_CIPHER *cipher = 0;
|
2005-07-07 00:54:12 +00:00
|
|
|
if(pbe == PBES2_TripleDES_SHA1)
|
2005-03-14 11:38:23 +00:00
|
|
|
cipher = EVP_des_ede3_cbc();
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(pbe == PBES2_DES_SHA1)
|
2005-03-14 11:38:23 +00:00
|
|
|
cipher = EVP_des_cbc();
|
|
|
|
|
|
|
|
if(!cipher)
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
EVP_PKEY *pkey = get_pkey();
|
|
|
|
|
|
|
|
// OpenSSL does not have DH import/export support
|
|
|
|
if(pkey->type == EVP_PKEY_DH)
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
BIO *bo = BIO_new(BIO_s_mem());
|
|
|
|
if(!passphrase.isEmpty())
|
|
|
|
PEM_write_bio_PKCS8PrivateKey(bo, pkey, cipher, NULL, 0, NULL, (void *)passphrase.data());
|
|
|
|
else
|
|
|
|
PEM_write_bio_PKCS8PrivateKey(bo, pkey, NULL, NULL, 0, NULL, NULL);
|
|
|
|
QSecureArray buf = bio2buf(bo);
|
|
|
|
return QString::fromLatin1(buf.toByteArray());
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual ConvertResult privateFromDER(const QSecureArray &in, const QSecureArray &passphrase)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
delete k;
|
|
|
|
k = 0;
|
|
|
|
|
|
|
|
EVP_PKEY *pkey;
|
|
|
|
if(!passphrase.isEmpty())
|
2005-04-09 22:46:24 +00:00
|
|
|
pkey = qca_d2i_PKCS8PrivateKey(in, NULL, NULL, (void *)passphrase.data());
|
2005-03-14 11:38:23 +00:00
|
|
|
else
|
2005-04-09 22:46:24 +00:00
|
|
|
pkey = qca_d2i_PKCS8PrivateKey(in, NULL, &passphrase_cb, NULL);
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
if(!pkey)
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
k = pkeyToBase(pkey, true);
|
|
|
|
if(k)
|
2005-07-07 00:54:12 +00:00
|
|
|
return ConvertGood;
|
2005-03-14 11:38:23 +00:00
|
|
|
else
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual ConvertResult privateFromPEM(const QString &s, const QSecureArray &passphrase)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
delete k;
|
|
|
|
k = 0;
|
|
|
|
|
|
|
|
QByteArray in = s.toLatin1();
|
|
|
|
BIO *bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, in.data(), in.size());
|
|
|
|
EVP_PKEY *pkey;
|
|
|
|
if(!passphrase.isEmpty())
|
|
|
|
pkey = PEM_read_bio_PrivateKey(bi, NULL, NULL, (void *)passphrase.data());
|
|
|
|
else
|
|
|
|
pkey = PEM_read_bio_PrivateKey(bi, NULL, &passphrase_cb, NULL);
|
|
|
|
BIO_free(bi);
|
|
|
|
|
|
|
|
if(!pkey)
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
k = pkeyToBase(pkey, true);
|
|
|
|
if(k)
|
2005-07-07 00:54:12 +00:00
|
|
|
return ConvertGood;
|
2005-03-14 11:38:23 +00:00
|
|
|
else
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// MyCertContext
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class X509Item
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
X509 *cert;
|
|
|
|
X509_REQ *req;
|
|
|
|
X509_CRL *crl;
|
|
|
|
|
|
|
|
enum Type { TypeCert, TypeReq, TypeCRL };
|
|
|
|
|
|
|
|
X509Item()
|
|
|
|
{
|
|
|
|
cert = 0;
|
|
|
|
req = 0;
|
|
|
|
crl = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
X509Item(const X509Item &from)
|
|
|
|
{
|
|
|
|
cert = from.cert;
|
|
|
|
req = from.req;
|
|
|
|
crl = from.crl;
|
|
|
|
|
|
|
|
if(cert)
|
|
|
|
CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
|
|
|
|
if(req)
|
|
|
|
CRYPTO_add(&req->references, 1, CRYPTO_LOCK_X509_REQ);
|
|
|
|
if(crl)
|
|
|
|
CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL);
|
|
|
|
}
|
|
|
|
|
|
|
|
~X509Item()
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
if(cert)
|
|
|
|
{
|
|
|
|
X509_free(cert);
|
|
|
|
cert = 0;
|
|
|
|
}
|
|
|
|
if(req)
|
|
|
|
{
|
|
|
|
X509_REQ_free(req);
|
|
|
|
req = 0;
|
|
|
|
}
|
|
|
|
if(crl)
|
|
|
|
{
|
|
|
|
X509_CRL_free(crl);
|
|
|
|
crl = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isNull() const
|
|
|
|
{
|
|
|
|
return (!cert && !req && !crl);
|
|
|
|
}
|
|
|
|
|
|
|
|
QSecureArray toDER() const
|
|
|
|
{
|
|
|
|
BIO *bo = BIO_new(BIO_s_mem());
|
|
|
|
if(cert)
|
|
|
|
i2d_X509_bio(bo, cert);
|
|
|
|
else if(req)
|
|
|
|
i2d_X509_REQ_bio(bo, req);
|
|
|
|
else if(crl)
|
|
|
|
i2d_X509_CRL_bio(bo, crl);
|
|
|
|
QSecureArray buf = bio2buf(bo);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString toPEM() const
|
|
|
|
{
|
|
|
|
BIO *bo = BIO_new(BIO_s_mem());
|
|
|
|
if(cert)
|
|
|
|
PEM_write_bio_X509(bo, cert);
|
|
|
|
else if(req)
|
|
|
|
PEM_write_bio_X509_REQ(bo, req);
|
|
|
|
else if(crl)
|
|
|
|
PEM_write_bio_X509_CRL(bo, crl);
|
|
|
|
QSecureArray buf = bio2buf(bo);
|
|
|
|
return QString::fromLatin1(buf.toByteArray());
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
ConvertResult fromDER(const QSecureArray &in, Type t)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
reset();
|
|
|
|
|
|
|
|
BIO *bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, in.data(), in.size());
|
|
|
|
|
|
|
|
if(t == TypeCert)
|
|
|
|
cert = d2i_X509_bio(bi, NULL);
|
|
|
|
else if(t == TypeReq)
|
|
|
|
req = d2i_X509_REQ_bio(bi, NULL);
|
|
|
|
else if(t == TypeCRL)
|
|
|
|
crl = d2i_X509_CRL_bio(bi, NULL);
|
|
|
|
|
|
|
|
BIO_free(bi);
|
|
|
|
|
|
|
|
if(isNull())
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
return ConvertGood;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
ConvertResult fromPEM(const QString &s, Type t)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
reset();
|
|
|
|
|
|
|
|
QByteArray in = s.toLatin1();
|
|
|
|
BIO *bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, in.data(), in.size());
|
|
|
|
|
|
|
|
if(t == TypeCert)
|
|
|
|
cert = PEM_read_bio_X509(bi, NULL, NULL, NULL);
|
|
|
|
else if(t == TypeReq)
|
|
|
|
req = PEM_read_bio_X509_REQ(bi, NULL, NULL, NULL);
|
|
|
|
else if(t == TypeCRL)
|
|
|
|
crl = PEM_read_bio_X509_CRL(bi, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
BIO_free(bi);
|
|
|
|
|
|
|
|
if(isNull())
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
return ConvertGood;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// (taken from kdelibs) -- Justin
|
|
|
|
//
|
|
|
|
// This code is mostly taken from OpenSSL v0.9.5a
|
|
|
|
// by Eric Young
|
|
|
|
QDateTime ASN1_UTCTIME_QDateTime(ASN1_UTCTIME *tm, int *isGmt)
|
|
|
|
{
|
|
|
|
QDateTime qdt;
|
|
|
|
char *v;
|
|
|
|
int gmt=0;
|
|
|
|
int i;
|
|
|
|
int y=0,M=0,d=0,h=0,m=0,s=0;
|
|
|
|
QDate qdate;
|
|
|
|
QTime qtime;
|
|
|
|
|
|
|
|
i = tm->length;
|
|
|
|
v = (char *)tm->data;
|
|
|
|
|
|
|
|
if (i < 10) goto auq_err;
|
|
|
|
if (v[i-1] == 'Z') gmt=1;
|
|
|
|
for (i=0; i<10; i++)
|
|
|
|
if ((v[i] > '9') || (v[i] < '0')) goto auq_err;
|
|
|
|
y = (v[0]-'0')*10+(v[1]-'0');
|
|
|
|
if (y < 50) y+=100;
|
|
|
|
M = (v[2]-'0')*10+(v[3]-'0');
|
|
|
|
if ((M > 12) || (M < 1)) goto auq_err;
|
|
|
|
d = (v[4]-'0')*10+(v[5]-'0');
|
|
|
|
h = (v[6]-'0')*10+(v[7]-'0');
|
|
|
|
m = (v[8]-'0')*10+(v[9]-'0');
|
|
|
|
if ( (v[10] >= '0') && (v[10] <= '9') &&
|
|
|
|
(v[11] >= '0') && (v[11] <= '9'))
|
|
|
|
s = (v[10]-'0')*10+(v[11]-'0');
|
|
|
|
|
|
|
|
// localize the date and display it.
|
|
|
|
qdate.setYMD(y+1900, M, d);
|
|
|
|
qtime.setHMS(h,m,s);
|
|
|
|
qdt.setDate(qdate); qdt.setTime(qtime);
|
|
|
|
auq_err:
|
|
|
|
if (isGmt) *isGmt = gmt;
|
|
|
|
return qdt;
|
|
|
|
}
|
|
|
|
|
2005-04-05 08:50:28 +00:00
|
|
|
// TODO: support read/write of multiple info values with the same name
|
2005-07-07 00:54:12 +00:00
|
|
|
class MyCertContext : public CertContext
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
X509Item item;
|
2005-07-07 00:54:12 +00:00
|
|
|
CertContextProps _props;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
MyCertContext(Provider *p) : CertContext(p)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-03-27 10:18:03 +00:00
|
|
|
//printf("[%p] ** created\n", this);
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
MyCertContext(const MyCertContext &from) : CertContext(from), item(from.item), _props(from._props)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-03-27 10:18:03 +00:00
|
|
|
//printf("[%p] ** created as copy (from [%p])\n", this, &from);
|
|
|
|
}
|
|
|
|
|
|
|
|
~MyCertContext()
|
|
|
|
{
|
|
|
|
//printf("[%p] ** deleted\n", this);
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider::Context *clone() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
return new MyCertContext(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QSecureArray toDER() const
|
|
|
|
{
|
|
|
|
return item.toDER();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QString toPEM() const
|
|
|
|
{
|
|
|
|
return item.toPEM();
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual ConvertResult fromDER(const QSecureArray &a)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
_props = CertContextProps();
|
|
|
|
ConvertResult r = item.fromDER(a, X509Item::TypeCert);
|
|
|
|
if(r == ConvertGood)
|
2005-03-14 11:38:23 +00:00
|
|
|
make_props();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual ConvertResult fromPEM(const QString &s)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
_props = CertContextProps();
|
|
|
|
ConvertResult r = item.fromPEM(s, X509Item::TypeCert);
|
|
|
|
if(r == ConvertGood)
|
2005-03-14 11:38:23 +00:00
|
|
|
make_props();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
void fromX509(X509 *x)
|
|
|
|
{
|
|
|
|
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
|
|
|
|
item.cert = x;
|
|
|
|
make_props();
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual bool createSelfSigned(const CertificateOptions &opts, const PKeyContext &priv)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
_props = CertContextProps();
|
2005-03-14 11:38:23 +00:00
|
|
|
item.reset();
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
CertificateInfo info = opts.info();
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
// constraints - logic from Botan
|
2005-07-07 00:54:12 +00:00
|
|
|
Constraints constraints;
|
2005-03-14 11:38:23 +00:00
|
|
|
if(opts.isCA())
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
constraints += KeyCertificateSign;
|
|
|
|
constraints += CRLSign;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
constraints = find_constraints(priv, opts.constraints());
|
|
|
|
|
|
|
|
EVP_PKEY *pk = static_cast<const MyPKeyContext *>(&priv)->get_pkey();
|
|
|
|
X509_EXTENSION *ex;
|
|
|
|
|
|
|
|
const EVP_MD *md;
|
2005-07-07 00:54:12 +00:00
|
|
|
if(priv.type() == PKey::RSA)
|
2005-03-14 11:38:23 +00:00
|
|
|
md = EVP_sha1();
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(priv.type() == PKey::DSA)
|
2005-03-14 11:38:23 +00:00
|
|
|
md = EVP_dss1();
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// create
|
|
|
|
X509 *x = X509_new();
|
|
|
|
X509_set_version(x, 2);
|
|
|
|
|
|
|
|
// serial
|
|
|
|
BIGNUM *bn = bi2bn(opts.serialNumber());
|
|
|
|
BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(x));
|
|
|
|
BN_free(bn);
|
|
|
|
|
|
|
|
// validity period
|
|
|
|
ASN1_TIME_set(X509_get_notBefore(x), opts.notValidBefore().toTime_t());
|
|
|
|
ASN1_TIME_set(X509_get_notAfter(x), opts.notValidAfter().toTime_t());
|
|
|
|
|
|
|
|
// public key
|
|
|
|
X509_set_pubkey(x, pk);
|
|
|
|
|
|
|
|
// subject
|
|
|
|
X509_NAME *name = new_cert_name(info);
|
|
|
|
X509_set_subject_name(x, name);
|
|
|
|
|
|
|
|
// issuer == subject
|
|
|
|
X509_set_issuer_name(x, name);
|
|
|
|
|
|
|
|
// subject key id
|
|
|
|
ex = new_subject_key_id(x);
|
|
|
|
{
|
|
|
|
X509_add_ext(x, ex, -1);
|
|
|
|
X509_EXTENSION_free(ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// CA mode
|
|
|
|
ex = new_basic_constraints(opts.isCA(), opts.pathLimit());
|
|
|
|
if(ex)
|
|
|
|
{
|
|
|
|
X509_add_ext(x, ex, -1);
|
|
|
|
X509_EXTENSION_free(ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// subject alt name
|
|
|
|
ex = new_cert_subject_alt_name(info);
|
|
|
|
if(ex)
|
|
|
|
{
|
|
|
|
X509_add_ext(x, ex, -1);
|
|
|
|
X509_EXTENSION_free(ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// key usage
|
|
|
|
ex = new_cert_key_usage(constraints);
|
|
|
|
if(ex)
|
|
|
|
{
|
|
|
|
X509_add_ext(x, ex, -1);
|
|
|
|
X509_EXTENSION_free(ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// extended key usage
|
|
|
|
ex = new_cert_ext_key_usage(constraints);
|
|
|
|
if(ex)
|
|
|
|
{
|
|
|
|
X509_add_ext(x, ex, -1);
|
|
|
|
X509_EXTENSION_free(ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// policies
|
|
|
|
ex = new_cert_policies(opts.policies());
|
|
|
|
if(ex)
|
|
|
|
{
|
|
|
|
X509_add_ext(x, ex, -1);
|
|
|
|
X509_EXTENSION_free(ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// finished
|
|
|
|
X509_sign(x, pk, md);
|
|
|
|
|
|
|
|
item.cert = x;
|
|
|
|
make_props();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual const CertContextProps *props() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-03-27 10:18:03 +00:00
|
|
|
//printf("[%p] grabbing props\n", this);
|
2005-03-14 11:38:23 +00:00
|
|
|
return &_props;
|
|
|
|
}
|
|
|
|
|
|
|
|
// does a new
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual PKeyContext *subjectPublicKey() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
MyPKeyContext *kc = new MyPKeyContext(provider());
|
|
|
|
EVP_PKEY *pkey = X509_get_pubkey(item.cert);
|
2005-07-07 00:54:12 +00:00
|
|
|
PKeyBase *kb = kc->pkeyToBase(pkey, false);
|
2005-03-14 11:38:23 +00:00
|
|
|
kc->setKey(kb);
|
|
|
|
return kc;
|
|
|
|
}
|
|
|
|
|
2005-03-28 07:11:58 +00:00
|
|
|
// implemented later because it depends on MyCRLContext
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Validity validate(const QList<CertContext*> &trusted, const QList<CertContext*> &untrusted, const QList<CRLContext *> &crls, UsageMode u) const;
|
2005-03-28 07:11:58 +00:00
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
void make_props()
|
|
|
|
{
|
|
|
|
X509 *x = item.cert;
|
2005-07-07 00:54:12 +00:00
|
|
|
CertContextProps p;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
p.version = X509_get_version(x);
|
|
|
|
|
|
|
|
ASN1_INTEGER *ai = X509_get_serialNumber(x);
|
|
|
|
if(ai)
|
|
|
|
{
|
|
|
|
char *rep = i2s_ASN1_INTEGER(NULL, ai);
|
|
|
|
QString str = rep;
|
|
|
|
OPENSSL_free(rep);
|
|
|
|
p.serial.fromString(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
p.start = ASN1_UTCTIME_QDateTime(X509_get_notBefore(x), NULL);
|
|
|
|
p.end = ASN1_UTCTIME_QDateTime(X509_get_notAfter(x), NULL);
|
|
|
|
|
|
|
|
p.subject = get_cert_name(X509_get_subject_name(x));
|
|
|
|
p.issuer = get_cert_name(X509_get_issuer_name(x));
|
|
|
|
|
2005-04-30 07:33:22 +00:00
|
|
|
p.isSelfSigned = ( X509_V_OK == X509_check_issued( x, x ) );
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
p.isCA = false;
|
|
|
|
p.pathLimit = 0;
|
|
|
|
int pos = X509_get_ext_by_NID(x, NID_basic_constraints, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509_get_ext(x, pos);
|
|
|
|
if(ex)
|
|
|
|
get_basic_constraints(ex, &p.isCA, &p.pathLimit);
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = X509_get_ext_by_NID(x, NID_subject_alt_name, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509_get_ext(x, pos);
|
|
|
|
if(ex)
|
|
|
|
p.subject.unite(get_cert_subject_alt_name(ex));
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = X509_get_ext_by_NID(x, NID_key_usage, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509_get_ext(x, pos);
|
|
|
|
if(ex)
|
|
|
|
p.constraints = get_cert_key_usage(ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509_get_ext(x, pos);
|
|
|
|
if(ex)
|
|
|
|
p.constraints += get_cert_ext_key_usage(ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = X509_get_ext_by_NID(x, NID_certificate_policies, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509_get_ext(x, pos);
|
|
|
|
if(ex)
|
|
|
|
p.policies = get_cert_policies(ex);
|
|
|
|
}
|
|
|
|
|
2006-02-03 09:22:55 +00:00
|
|
|
if (x->signature)
|
|
|
|
{
|
|
|
|
p.sig = QSecureArray(x->signature->length);
|
|
|
|
for (int i=0; i< x->signature->length; i++)
|
|
|
|
p.sig[i] = x->signature->data[i];
|
|
|
|
}
|
2006-02-01 10:09:29 +00:00
|
|
|
|
|
|
|
switch( OBJ_obj2nid(x->cert_info->signature->algorithm) )
|
|
|
|
{
|
|
|
|
case NID_sha1WithRSAEncryption:
|
|
|
|
p.sigalgo = QCA::EMSA3_SHA1;
|
|
|
|
break;
|
|
|
|
case NID_md5WithRSAEncryption:
|
|
|
|
p.sigalgo = QCA::EMSA3_MD5;
|
|
|
|
break;
|
|
|
|
case NID_md2WithRSAEncryption:
|
|
|
|
p.sigalgo = QCA::EMSA3_MD2;
|
|
|
|
break;
|
|
|
|
case NID_ripemd160WithRSA:
|
|
|
|
p.sigalgo = QCA::EMSA3_RIPEMD160;
|
|
|
|
break;
|
|
|
|
case NID_dsaWithSHA1:
|
|
|
|
p.sigalgo = QCA::EMSA1_SHA1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
qDebug() << "Unknown signature value: " << OBJ_obj2nid(x->cert_info->signature->algorithm);
|
|
|
|
p.sigalgo = QCA::SignatureUnknown;
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-05 07:57:40 +00:00
|
|
|
pos = X509_get_ext_by_NID(x, NID_subject_key_identifier, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509_get_ext(x, pos);
|
|
|
|
if(ex)
|
|
|
|
p.subjectId += get_cert_subject_key_id(ex);
|
|
|
|
}
|
|
|
|
|
2006-02-01 10:09:29 +00:00
|
|
|
pos = X509_get_ext_by_NID(x, NID_authority_key_identifier, -1);
|
2005-04-05 07:57:40 +00:00
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509_get_ext(x, pos);
|
|
|
|
if(ex)
|
|
|
|
p.issuerId += get_cert_issuer_key_id(ex);
|
2006-02-01 10:09:29 +00:00
|
|
|
}
|
2005-04-05 07:57:40 +00:00
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
_props = p;
|
2005-07-07 00:54:12 +00:00
|
|
|
//printf("[%p] made props: [%s]\n", this, _props.subject[CommonName].toLatin1().data());
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// MyCSRContext
|
|
|
|
//----------------------------------------------------------------------------
|
2005-07-07 00:54:12 +00:00
|
|
|
class MyCSRContext : public CSRContext
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
X509Item item;
|
2005-07-07 00:54:12 +00:00
|
|
|
CertContextProps _props;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
MyCSRContext(Provider *p) : CSRContext(p)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
MyCSRContext(const MyCSRContext &from) : CSRContext(from), item(from.item), _props(from._props)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider::Context *clone() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
return new MyCSRContext(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QSecureArray toDER() const
|
|
|
|
{
|
|
|
|
return item.toDER();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QString toPEM() const
|
|
|
|
{
|
|
|
|
return item.toPEM();
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual ConvertResult fromDER(const QSecureArray &a)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
_props = CertContextProps();
|
|
|
|
ConvertResult r = item.fromDER(a, X509Item::TypeReq);
|
|
|
|
if(r == ConvertGood)
|
2005-03-14 11:38:23 +00:00
|
|
|
make_props();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual ConvertResult fromPEM(const QString &s)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
_props = CertContextProps();
|
|
|
|
ConvertResult r = item.fromPEM(s, X509Item::TypeReq);
|
|
|
|
if(r == ConvertGood)
|
2005-03-14 11:38:23 +00:00
|
|
|
make_props();
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual bool canUseFormat(CertificateRequestFormat f) const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
if(f == PKCS10)
|
2005-03-14 11:38:23 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual bool createRequest(const CertificateOptions &opts, const PKeyContext &priv)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
_props = CertContextProps();
|
2005-03-14 11:38:23 +00:00
|
|
|
item.reset();
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
CertificateInfo info = opts.info();
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
// constraints - logic from Botan
|
2005-07-07 00:54:12 +00:00
|
|
|
Constraints constraints;
|
2005-03-14 11:38:23 +00:00
|
|
|
if(opts.isCA())
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
constraints += KeyCertificateSign;
|
|
|
|
constraints += CRLSign;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
constraints = find_constraints(priv, opts.constraints());
|
|
|
|
|
|
|
|
EVP_PKEY *pk = static_cast<const MyPKeyContext *>(&priv)->get_pkey();
|
|
|
|
X509_EXTENSION *ex;
|
|
|
|
|
|
|
|
const EVP_MD *md;
|
2005-07-07 00:54:12 +00:00
|
|
|
if(priv.type() == PKey::RSA)
|
2005-03-14 11:38:23 +00:00
|
|
|
md = EVP_sha1();
|
2005-07-07 00:54:12 +00:00
|
|
|
else if(priv.type() == PKey::DSA)
|
2005-03-14 11:38:23 +00:00
|
|
|
md = EVP_dss1();
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// create
|
|
|
|
X509_REQ *x = X509_REQ_new();
|
|
|
|
|
|
|
|
// public key
|
|
|
|
X509_REQ_set_pubkey(x, pk);
|
|
|
|
|
|
|
|
// subject
|
|
|
|
X509_NAME *name = new_cert_name(info);
|
|
|
|
X509_REQ_set_subject_name(x, name);
|
|
|
|
|
|
|
|
// challenge
|
|
|
|
QByteArray cs = opts.challenge().toLatin1();
|
|
|
|
if(!cs.isEmpty())
|
|
|
|
X509_REQ_add1_attr_by_NID(x, NID_pkcs9_challengePassword, MBSTRING_UTF8, (const unsigned char *)cs.data(), -1);
|
|
|
|
|
|
|
|
STACK_OF(X509_EXTENSION) *exts = sk_X509_EXTENSION_new_null();
|
|
|
|
|
|
|
|
// CA mode
|
|
|
|
ex = new_basic_constraints(opts.isCA(), opts.pathLimit());
|
|
|
|
if(ex)
|
|
|
|
sk_X509_EXTENSION_push(exts, ex);
|
|
|
|
|
|
|
|
// subject alt name
|
|
|
|
ex = new_cert_subject_alt_name(info);
|
|
|
|
if(ex)
|
|
|
|
sk_X509_EXTENSION_push(exts, ex);
|
|
|
|
|
|
|
|
// key usage
|
|
|
|
ex = new_cert_key_usage(constraints);
|
|
|
|
if(ex)
|
|
|
|
sk_X509_EXTENSION_push(exts, ex);
|
|
|
|
|
|
|
|
// extended key usage
|
|
|
|
ex = new_cert_ext_key_usage(constraints);
|
|
|
|
if(ex)
|
|
|
|
sk_X509_EXTENSION_push(exts, ex);
|
|
|
|
|
|
|
|
// policies
|
|
|
|
ex = new_cert_policies(opts.policies());
|
|
|
|
if(ex)
|
|
|
|
sk_X509_EXTENSION_push(exts, ex);
|
|
|
|
|
|
|
|
if(sk_X509_EXTENSION_num(exts) > 0)
|
|
|
|
X509_REQ_add_extensions(x, exts);
|
|
|
|
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
|
|
|
|
|
|
|
|
// finished
|
|
|
|
X509_REQ_sign(x, pk, md);
|
|
|
|
|
|
|
|
item.req = x;
|
|
|
|
make_props();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual const CertContextProps *props() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
return &_props;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual PKeyContext *subjectPublicKey() const // does a new
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
MyPKeyContext *kc = new MyPKeyContext(provider());
|
|
|
|
EVP_PKEY *pkey = X509_REQ_get_pubkey(item.req);
|
2005-07-07 00:54:12 +00:00
|
|
|
PKeyBase *kb = kc->pkeyToBase(pkey, false);
|
2005-03-14 11:38:23 +00:00
|
|
|
kc->setKey(kb);
|
|
|
|
return kc;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QString toSPKAC() const
|
|
|
|
{
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual ConvertResult fromSPKAC(const QString &s)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
Q_UNUSED(s);
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void make_props()
|
|
|
|
{
|
|
|
|
X509_REQ *x = item.req;
|
2005-07-07 00:54:12 +00:00
|
|
|
CertContextProps p;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
// TODO: QString challenge;
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
p.format = PKCS10;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
|
|
|
p.subject = get_cert_name(X509_REQ_get_subject_name(x));
|
|
|
|
|
|
|
|
STACK_OF(X509_EXTENSION) *exts = X509_REQ_get_extensions(x);
|
|
|
|
|
|
|
|
p.isCA = false;
|
|
|
|
p.pathLimit = 0;
|
|
|
|
int pos = X509v3_get_ext_by_NID(exts, NID_basic_constraints, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509v3_get_ext(exts, pos);
|
|
|
|
if(ex)
|
|
|
|
get_basic_constraints(ex, &p.isCA, &p.pathLimit);
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = X509v3_get_ext_by_NID(exts, NID_subject_alt_name, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509v3_get_ext(exts, pos);
|
|
|
|
if(ex)
|
|
|
|
p.subject.unite(get_cert_subject_alt_name(ex));
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = X509v3_get_ext_by_NID(exts, NID_key_usage, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509v3_get_ext(exts, pos);
|
|
|
|
if(ex)
|
|
|
|
p.constraints = get_cert_key_usage(ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = X509v3_get_ext_by_NID(exts, NID_ext_key_usage, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509v3_get_ext(exts, pos);
|
|
|
|
if(ex)
|
|
|
|
p.constraints += get_cert_ext_key_usage(ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = X509v3_get_ext_by_NID(exts, NID_certificate_policies, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509v3_get_ext(exts, pos);
|
|
|
|
if(ex)
|
|
|
|
p.policies = get_cert_policies(ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
|
|
|
|
|
2006-02-26 04:16:12 +00:00
|
|
|
if (x->signature)
|
|
|
|
{
|
|
|
|
p.sig = QSecureArray(x->signature->length);
|
|
|
|
for (int i=0; i< x->signature->length; i++)
|
|
|
|
p.sig[i] = x->signature->data[i];
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2006-02-26 04:16:12 +00:00
|
|
|
switch( OBJ_obj2nid(x->sig_alg->algorithm) )
|
|
|
|
{
|
|
|
|
case NID_sha1WithRSAEncryption:
|
|
|
|
p.sigalgo = QCA::EMSA3_SHA1;
|
|
|
|
break;
|
|
|
|
case NID_md5WithRSAEncryption:
|
|
|
|
p.sigalgo = QCA::EMSA3_MD5;
|
|
|
|
break;
|
|
|
|
case NID_md2WithRSAEncryption:
|
|
|
|
p.sigalgo = QCA::EMSA3_MD2;
|
|
|
|
break;
|
|
|
|
case NID_ripemd160WithRSA:
|
|
|
|
p.sigalgo = QCA::EMSA3_RIPEMD160;
|
|
|
|
break;
|
|
|
|
case NID_dsaWithSHA1:
|
|
|
|
p.sigalgo = QCA::EMSA1_SHA1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
qDebug() << "Unknown signature value: " << OBJ_obj2nid(x->sig_alg->algorithm);
|
|
|
|
p.sigalgo = QCA::SignatureUnknown;
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
_props = p;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// MyCRLContext
|
|
|
|
//----------------------------------------------------------------------------
|
2005-07-07 00:54:12 +00:00
|
|
|
class MyCRLContext : public CRLContext
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
X509Item item;
|
2006-02-22 07:01:29 +00:00
|
|
|
CRLContextProps _props;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
MyCRLContext(Provider *p) : CRLContext(p)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
MyCRLContext(const MyCRLContext &from) : CRLContext(from), item(from.item)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider::Context *clone() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
return new MyCRLContext(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QSecureArray toDER() const
|
|
|
|
{
|
|
|
|
return item.toDER();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QString toPEM() const
|
|
|
|
{
|
|
|
|
return item.toPEM();
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual ConvertResult fromDER(const QSecureArray &a)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2006-02-22 07:01:29 +00:00
|
|
|
ConvertResult r = item.fromDER(a, X509Item::TypeCRL);
|
|
|
|
if(r == ConvertGood)
|
|
|
|
make_props();
|
|
|
|
return r;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual ConvertResult fromPEM(const QString &s)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2006-02-22 07:01:29 +00:00
|
|
|
ConvertResult r = item.fromPEM(s, X509Item::TypeCRL);
|
|
|
|
if(r == ConvertGood)
|
|
|
|
make_props();
|
|
|
|
return r;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual const CRLContextProps *props() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2006-02-22 07:01:29 +00:00
|
|
|
return &_props;
|
|
|
|
}
|
|
|
|
|
|
|
|
void make_props()
|
|
|
|
{
|
|
|
|
X509_CRL *x = item.crl;
|
|
|
|
|
|
|
|
CRLContextProps p;
|
|
|
|
|
|
|
|
p.issuer = get_cert_name(X509_CRL_get_issuer(x));
|
|
|
|
|
|
|
|
p.thisUpdate = ASN1_UTCTIME_QDateTime(X509_CRL_get_lastUpdate(x), NULL);
|
|
|
|
p.nextUpdate = ASN1_UTCTIME_QDateTime(X509_CRL_get_nextUpdate(x), NULL);
|
|
|
|
|
|
|
|
STACK_OF(X509_REVOKED)* revokeStack = X509_CRL_get_REVOKED(x);
|
|
|
|
|
|
|
|
for (int i = 0; i < sk_X509_REVOKED_num(revokeStack); ++i) {
|
|
|
|
X509_REVOKED *rev = sk_X509_REVOKED_value(revokeStack, i);
|
|
|
|
QBigInteger serial = bn2bi(ASN1_INTEGER_to_BN(rev->serialNumber, NULL));
|
|
|
|
QDateTime time = ASN1_UTCTIME_QDateTime( rev->revocationDate, NULL);
|
|
|
|
QCA::CRLEntry::Reason reason = QCA::CRLEntry::Unspecified;
|
|
|
|
int pos = X509_REVOKED_get_ext_by_NID(rev, NID_crl_reason, -1);
|
|
|
|
if (pos != -1) {
|
|
|
|
X509_EXTENSION *ex = X509_REVOKED_get_ext(rev, pos);
|
|
|
|
if(ex) {
|
|
|
|
int *result = (int*) X509V3_EXT_d2i(ex);
|
|
|
|
switch (*result) {
|
|
|
|
case 0:
|
|
|
|
reason = QCA::CRLEntry::Unspecified;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
reason = QCA::CRLEntry::KeyCompromise;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
reason = QCA::CRLEntry::CACompromise;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
reason = QCA::CRLEntry::AffiliationChanged;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
reason = QCA::CRLEntry::Superseded;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
reason = QCA::CRLEntry::CessationOfOperation;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
reason = QCA::CRLEntry::CertificateHold;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
reason = QCA::CRLEntry::RemoveFromCRL;
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
reason = QCA::CRLEntry::PrivilegeWithdrawn;
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
reason = QCA::CRLEntry::AACompromise;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
reason = QCA::CRLEntry::Unspecified;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ASN1_INTEGER_free((ASN1_INTEGER*)result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CRLEntry thisEntry( serial, time, reason);
|
|
|
|
p.revoked.append(thisEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x->signature)
|
|
|
|
{
|
|
|
|
p.sig = QSecureArray(x->signature->length);
|
|
|
|
for (int i=0; i< x->signature->length; i++)
|
|
|
|
p.sig[i] = x->signature->data[i];
|
|
|
|
}
|
|
|
|
switch( OBJ_obj2nid(x->sig_alg->algorithm) )
|
|
|
|
{
|
|
|
|
case NID_sha1WithRSAEncryption:
|
|
|
|
p.sigalgo = QCA::EMSA3_SHA1;
|
|
|
|
break;
|
|
|
|
case NID_md5WithRSAEncryption:
|
|
|
|
p.sigalgo = QCA::EMSA3_MD5;
|
|
|
|
break;
|
|
|
|
case NID_md2WithRSAEncryption:
|
|
|
|
p.sigalgo = QCA::EMSA3_MD2;
|
|
|
|
break;
|
|
|
|
case NID_ripemd160WithRSA:
|
|
|
|
p.sigalgo = QCA::EMSA3_RIPEMD160;
|
|
|
|
break;
|
|
|
|
case NID_dsaWithSHA1:
|
|
|
|
p.sigalgo = QCA::EMSA1_SHA1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
qWarning() << "Unknown signature value: " << OBJ_obj2nid(x->sig_alg->algorithm);
|
|
|
|
p.sigalgo = QCA::SignatureUnknown;
|
|
|
|
}
|
|
|
|
|
|
|
|
int pos = X509_CRL_get_ext_by_NID(x, NID_authority_key_identifier, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509_CRL_get_ext(x, pos);
|
|
|
|
if(ex)
|
|
|
|
p.issuerId += get_cert_issuer_key_id(ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
p.number = -1;
|
|
|
|
pos = X509_CRL_get_ext_by_NID(x, NID_crl_number, -1);
|
|
|
|
if(pos != -1)
|
|
|
|
{
|
|
|
|
X509_EXTENSION *ex = X509_CRL_get_ext(x, pos);
|
|
|
|
if(ex) {
|
|
|
|
int *result = (int*) X509V3_EXT_d2i(ex);
|
|
|
|
p.number = (*result);
|
|
|
|
ASN1_INTEGER_free((ASN1_INTEGER*)result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_props = p;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
static bool usage_check(const MyCertContext &cc, UsageMode u)
|
2005-03-28 07:11:58 +00:00
|
|
|
{
|
2005-05-07 07:32:18 +00:00
|
|
|
if (cc._props.constraints.isEmpty() ) {
|
|
|
|
// then any usage is OK
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-05-06 11:09:29 +00:00
|
|
|
switch (u)
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
case UsageAny :
|
2005-05-06 11:09:29 +00:00
|
|
|
return true;
|
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case UsageTLSServer :
|
|
|
|
return cc._props.constraints.contains(ServerAuth);
|
2005-05-06 11:09:29 +00:00
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case UsageTLSClient :
|
|
|
|
return cc._props.constraints.contains(ClientAuth);
|
2005-05-06 11:09:29 +00:00
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case UsageCodeSigning :
|
|
|
|
return cc._props.constraints.contains(CodeSigning);
|
2005-05-06 11:09:29 +00:00
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case UsageEmailProtection :
|
|
|
|
return cc._props.constraints.contains(EmailProtection);
|
2005-05-06 11:09:29 +00:00
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case UsageTimeStamping :
|
|
|
|
return cc._props.constraints.contains(TimeStamping);
|
2005-05-06 11:09:29 +00:00
|
|
|
break;
|
2005-07-07 00:54:12 +00:00
|
|
|
case UsageCRLSigning :
|
|
|
|
return cc._props.constraints.contains(CRLSign);
|
2005-05-06 11:09:29 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
2005-03-28 07:11:58 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
Validity MyCertContext::validate(const QList<CertContext*> &trusted, const QList<CertContext*> &untrusted, const QList<CRLContext *> &crls, UsageMode u) const
|
2005-03-28 07:11:58 +00:00
|
|
|
{
|
|
|
|
STACK_OF(X509) *trusted_list = sk_X509_new_null();
|
|
|
|
STACK_OF(X509) *untrusted_list = sk_X509_new_null();
|
|
|
|
QList<X509_CRL*> crl_list;
|
|
|
|
|
|
|
|
int n;
|
|
|
|
for(n = 0; n < trusted.count(); ++n)
|
|
|
|
{
|
|
|
|
const MyCertContext *cc = static_cast<const MyCertContext *>(trusted[n]);
|
|
|
|
X509 *x = cc->item.cert;
|
|
|
|
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
|
|
|
|
sk_X509_push(trusted_list, x);
|
|
|
|
}
|
|
|
|
for(n = 0; n < untrusted.count(); ++n)
|
|
|
|
{
|
|
|
|
const MyCertContext *cc = static_cast<const MyCertContext *>(untrusted[n]);
|
|
|
|
X509 *x = cc->item.cert;
|
|
|
|
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
|
|
|
|
sk_X509_push(untrusted_list, x);
|
|
|
|
}
|
|
|
|
for(n = 0; n < crls.count(); ++n)
|
|
|
|
{
|
|
|
|
const MyCRLContext *cc = static_cast<const MyCRLContext *>(crls[n]);
|
|
|
|
X509_CRL *x = cc->item.crl;
|
|
|
|
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL);
|
|
|
|
crl_list.append(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
const MyCertContext *cc = this;
|
|
|
|
X509 *x = cc->item.cert;
|
|
|
|
|
|
|
|
// verification happens through a store "context"
|
|
|
|
X509_STORE_CTX *ctx = X509_STORE_CTX_new();
|
|
|
|
|
|
|
|
// make a store of crls
|
|
|
|
X509_STORE *store = X509_STORE_new();
|
|
|
|
for(int n = 0; n < crl_list.count(); ++n)
|
|
|
|
X509_STORE_add_crl(store, crl_list[n]);
|
|
|
|
|
|
|
|
// the first initialization handles untrusted certs, crls, and target cert
|
|
|
|
X509_STORE_CTX_init(ctx, store, x, untrusted_list);
|
|
|
|
|
|
|
|
// this initializes the trusted certs
|
|
|
|
X509_STORE_CTX_trusted_stack(ctx, trusted_list);
|
|
|
|
|
|
|
|
// verify!
|
|
|
|
int ret = X509_verify_cert(ctx);
|
|
|
|
int err = -1;
|
|
|
|
if(!ret)
|
|
|
|
err = ctx->error;
|
|
|
|
|
|
|
|
// cleanup
|
|
|
|
X509_STORE_CTX_free(ctx);
|
|
|
|
X509_STORE_free(store);
|
|
|
|
|
|
|
|
sk_X509_pop_free(trusted_list, X509_free);
|
|
|
|
sk_X509_pop_free(untrusted_list, X509_free);
|
|
|
|
for(int n = 0; n < crl_list.count(); ++n)
|
|
|
|
X509_CRL_free(crl_list[n]);
|
|
|
|
|
|
|
|
if(!ret)
|
|
|
|
return convert_verify_error(err);
|
|
|
|
|
|
|
|
if(!usage_check(*cc, u))
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorInvalidPurpose;
|
2005-03-28 07:11:58 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
return ValidityGood;
|
2005-03-28 07:11:58 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
class MyPIXContext : public PIXContext
|
2005-06-05 08:49:15 +00:00
|
|
|
{
|
|
|
|
public:
|
2005-07-07 00:54:12 +00:00
|
|
|
MyPIXContext(Provider *p) : PIXContext(p)
|
2005-06-05 08:49:15 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~MyPIXContext()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider::Context *clone() const
|
2005-06-05 08:49:15 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual QByteArray toPKCS12(const QString &name, const QList<const CertContext*> &chain, const PKeyContext &priv, const QSecureArray &passphrase) const
|
2005-06-05 08:49:15 +00:00
|
|
|
{
|
2005-06-25 04:04:29 +00:00
|
|
|
if(chain.count() < 1)
|
|
|
|
return QByteArray();
|
|
|
|
|
|
|
|
X509 *cert = static_cast<const MyCertContext *>(chain[0])->item.cert;
|
|
|
|
STACK_OF(X509) *ca = NULL;
|
|
|
|
if(chain.count() > 1)
|
|
|
|
{
|
|
|
|
for(int n = 1; n < chain.count(); ++n)
|
|
|
|
{
|
|
|
|
X509 *x = static_cast<const MyCertContext *>(chain[n])->item.cert;
|
|
|
|
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
|
|
|
|
sk_X509_push(ca, x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const MyPKeyContext &pk = static_cast<const MyPKeyContext &>(priv);
|
|
|
|
PKCS12 *p12 = PKCS12_create((char *)passphrase.data(), (char *)name.toLatin1().data(), pk.get_pkey(), cert, ca, 0, 0, 0, 0, 0);
|
|
|
|
sk_X509_pop_free(ca, X509_free);
|
|
|
|
|
|
|
|
if(!p12)
|
|
|
|
return QByteArray();
|
|
|
|
|
|
|
|
BIO *bo = BIO_new(BIO_s_mem());
|
|
|
|
i2d_PKCS12_bio(bo, p12);
|
|
|
|
QByteArray out = bio2ba(bo);
|
|
|
|
return out;
|
2005-06-05 08:49:15 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual ConvertResult fromPKCS12(const QByteArray &in, const QSecureArray &passphrase, QString *name, QList<CertContext*> *chain, PKeyContext **priv) const
|
2005-06-05 08:49:15 +00:00
|
|
|
{
|
2005-06-25 04:04:29 +00:00
|
|
|
BIO *bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, in.data(), in.size());
|
|
|
|
PKCS12 *p12 = d2i_PKCS12_bio(bi, NULL);
|
|
|
|
if(!p12)
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-06-25 04:04:29 +00:00
|
|
|
|
|
|
|
EVP_PKEY *pkey;
|
|
|
|
X509 *cert;
|
|
|
|
STACK_OF(X509) *ca = NULL;
|
|
|
|
if(!PKCS12_parse(p12, passphrase.data(), &pkey, &cert, &ca))
|
|
|
|
{
|
|
|
|
PKCS12_free(p12);
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-06-25 04:04:29 +00:00
|
|
|
}
|
|
|
|
PKCS12_free(p12);
|
|
|
|
|
|
|
|
// require private key
|
|
|
|
if(!pkey)
|
|
|
|
{
|
|
|
|
if(cert)
|
|
|
|
X509_free(cert);
|
|
|
|
if(ca)
|
|
|
|
sk_X509_pop_free(ca, X509_free);
|
2005-07-07 00:54:12 +00:00
|
|
|
return ErrorDecode;
|
2005-06-25 04:04:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*name = QString(); // TODO: read the name out of the file?
|
|
|
|
|
|
|
|
MyPKeyContext *pk = new MyPKeyContext(provider());
|
2005-07-07 00:54:12 +00:00
|
|
|
PKeyBase *k = pk->pkeyToBase(pkey, true); // does an EVP_PKEY_free()
|
2005-06-25 04:04:29 +00:00
|
|
|
pk->k = k;
|
|
|
|
*priv = pk;
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
QList<CertContext*> certs;
|
2005-06-25 04:04:29 +00:00
|
|
|
if(cert)
|
|
|
|
{
|
|
|
|
MyCertContext *cc = new MyCertContext(provider());
|
|
|
|
cc->fromX509(cert);
|
|
|
|
certs.append(cc);
|
|
|
|
X509_free(cert);
|
|
|
|
}
|
|
|
|
if(ca)
|
|
|
|
{
|
|
|
|
// TODO: reorder in chain-order?
|
|
|
|
// TODO: throw out certs that don't fit the chain?
|
|
|
|
for(int n = 0; n < sk_X509_num(ca); ++n)
|
|
|
|
{
|
|
|
|
MyCertContext *cc = new MyCertContext(provider());
|
|
|
|
cc->fromX509(sk_X509_value(ca, n));
|
|
|
|
certs.append(cc);
|
|
|
|
}
|
|
|
|
sk_X509_pop_free(ca, X509_free);
|
|
|
|
}
|
|
|
|
|
|
|
|
*chain = certs;
|
2005-07-07 00:54:12 +00:00
|
|
|
return ConvertGood;
|
2005-06-05 08:49:15 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2006-03-18 05:11:43 +00:00
|
|
|
//==========================================================
|
|
|
|
static QString cipherIDtoString( const TLS::Version &version, const unsigned long &cipherID)
|
|
|
|
{
|
|
|
|
if (TLS::TLS_v1 == version) {
|
|
|
|
switch( cipherID & 0xFFFF ) {
|
|
|
|
case 0x0000:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_NULL_WITH_NULL_NULL");
|
|
|
|
break;
|
|
|
|
case 0x0001:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_RSA_WITH_NULL_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0002:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_RSA_WITH_NULL_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0003:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_RSA_EXPORT_WITH_RC4_40_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0004:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_RSA_WITH_RC4_128_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0005:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_RSA_WITH_RC4_128_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0006:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0007:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_RSA_WITH_IDEA_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0008:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_RSA_EXPORT_WITH_DES40_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0009:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_RSA_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x000A:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_RSA_WITH_3DES_EDE_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x000B:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x000C:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DH_DSS_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x000D:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x000E:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x000F:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DH_RSA_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0010:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0011:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0012:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DHE_DSS_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0013:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0014:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0015:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DHE_RSA_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0016:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0017:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DH_anon_EXPORT_WITH_RC4_40_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0018:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DH_anon_WITH_RC4_128_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0019:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x001A:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DH_anon_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x001B:
|
|
|
|
// RFC 2246 A.5
|
|
|
|
return QString("TLS_DH_anon_WITH_3DES_EDE_CBC_SHA");
|
|
|
|
break;
|
|
|
|
|
|
|
|
// 0x001C and 0x001D are reserved to avoid collision with SSL3 Fortezza.
|
|
|
|
|
|
|
|
// TODO: 0x001E -> 0x002B are from RFC2712.
|
|
|
|
|
|
|
|
case 0x002F:
|
|
|
|
// RFC 3268
|
|
|
|
return QString("TLS_RSA_WITH_AES_128_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0030:
|
|
|
|
// RFC 3268
|
|
|
|
return QString("TLS_DH_DSS_WITH_AES_128_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0031:
|
|
|
|
// RFC 3268
|
|
|
|
return QString("TLS_DH_RSA_WITH_AES_128_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0032:
|
|
|
|
// RFC 3268
|
|
|
|
return QString("TLS_DHE_DSS_WITH_AES_128_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0033:
|
|
|
|
// RFC 3268
|
|
|
|
return QString("TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0034:
|
|
|
|
// RFC 3268
|
|
|
|
return QString("TLS_DH_anon_WITH_AES_128_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0035:
|
|
|
|
// RFC 3268
|
|
|
|
return QString("TLS_RSA_WITH_AES_256_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0036:
|
|
|
|
// RFC 3268
|
|
|
|
return QString("TLS_DH_DSS_WITH_AES_256_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0037:
|
|
|
|
// RFC 3268
|
|
|
|
return QString("TLS_DH_RSA_WITH_AES_256_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0038:
|
|
|
|
// RFC 3268
|
|
|
|
return QString("TLS_DHE_DSS_WITH_AES_256_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0039:
|
|
|
|
// RFC 3268
|
|
|
|
return QString("TLS_DHE_RSA_WITH_AES_256_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x003A:
|
|
|
|
// RFC 3268
|
|
|
|
return QString("TLS_DH_anon_WITH_AES_256_CBC_SHA");
|
|
|
|
break;
|
|
|
|
|
|
|
|
// TODO: 0x0041 -> 0x0046 are from RFC4132 (Camellia)
|
|
|
|
|
|
|
|
case 0x0060:
|
|
|
|
// Was meant to be from draft-ietf-tls-56-bit-ciphersuites-01.txt, but isn't
|
|
|
|
return QString("TLS_CK_RSA_EXPORT1024_WITH_RC4_56_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0061:
|
|
|
|
// Was meant to be from draft-ietf-tls-56-bit-ciphersuites-01.txt, but isn't
|
|
|
|
return QString("TLS_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0062:
|
|
|
|
// Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt
|
|
|
|
return QString("TLS_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0063:
|
|
|
|
// Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt
|
|
|
|
return QString("TLS_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0064:
|
|
|
|
// Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt
|
|
|
|
return QString("TLS_CK_RSA_EXPORT1024_WITH_RC4_56_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0065:
|
|
|
|
// Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt
|
|
|
|
return QString("TLS_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0066:
|
|
|
|
// Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt
|
|
|
|
return QString("TLS_CK_DHE_DSS_WITH_RC4_128_SHA");
|
|
|
|
break;
|
|
|
|
|
|
|
|
// TODO: 0x0084 -> 0x0089 are from RFC4132 (Camellia)
|
|
|
|
|
|
|
|
// TODO: 0x008A -> 0x0095 are from RFC4279 (PSK)
|
|
|
|
|
|
|
|
// TODO: 0xC000 -> 0xC019 are from the ECC draft
|
|
|
|
|
|
|
|
default:
|
|
|
|
return QString("TLS algo to be added: %1").arg(cipherID & 0xffff, 0, 16);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (TLS::SSL_v3 == version) {
|
|
|
|
switch( cipherID & 0xFFFF ) {
|
|
|
|
case 0x0000:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_NULL_WITH_NULL_NULL");
|
|
|
|
break;
|
|
|
|
case 0x0001:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_RSA_WITH_NULL_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0002:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_RSA_WITH_NULL_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0003:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_RSA_EXPORT_WITH_RC4_40_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0004:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_RSA_WITH_RC4_128_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0005:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_RSA_WITH_RC4_128_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0006:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0007:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_RSA_WITH_IDEA_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0008:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0009:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_RSA_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x000A:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_RSA_WITH_3DES_EDE_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x000B:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x000C:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DH_DSS_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x000D:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x000E:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DH_RSA_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x000F:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DH_RSA_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0010:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0011:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0012:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DHE_DSS_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0013:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0014:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0015:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DHE_RSA_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0016:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0017:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SL_DH_anon_EXPORT_WITH_RC4_40_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0018:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DH_anon_WITH_RC4_128_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0019:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x001A:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DH_anon_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x001B:
|
|
|
|
// From the Netscape SSL3 Draft (nov 1996)
|
|
|
|
return QString("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA");
|
|
|
|
break;
|
|
|
|
|
|
|
|
// TODO: Sort out the Fortezza mess...
|
|
|
|
|
|
|
|
// These aren't in the Netscape SSL3 draft, but openssl does
|
|
|
|
// allow you to use them with SSL3.
|
|
|
|
case 0x002F:
|
|
|
|
return QString("SSL_RSA_WITH_AES_128_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0030:
|
|
|
|
return QString("SSL_DH_DSS_WITH_AES_128_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0031:
|
|
|
|
return QString("SSL_DH_RSA_WITH_AES_128_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0032:
|
|
|
|
return QString("SSL_DHE_DSS_WITH_AES_128_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0033:
|
|
|
|
return QString("SSL_DHE_RSA_WITH_AES_128_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0034:
|
|
|
|
return QString("SSL_DH_anon_WITH_AES_128_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0035:
|
|
|
|
return QString("SSL_RSA_WITH_AES_256_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0036:
|
|
|
|
return QString("SSL_DH_DSS_WITH_AES_256_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0037:
|
|
|
|
return QString("SSL_DH_RSA_WITH_AES_256_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0038:
|
|
|
|
return QString("SSL_DHE_DSS_WITH_AES_256_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0039:
|
|
|
|
return QString("SSL_DHE_RSA_WITH_AES_256_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x003A:
|
|
|
|
return QString("SSL_DH_anon_WITH_AES_256_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0060:
|
|
|
|
// Was meant to be from draft-ietf-tls-56-bit-ciphersuites-01.txt, but isn't
|
|
|
|
return QString("SSL_CK_RSA_EXPORT1024_WITH_RC4_56_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0061:
|
|
|
|
// Was meant to be from draft-ietf-tls-56-bit-ciphersuites-01.txt, but isn't
|
|
|
|
return QString("SSL_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0062:
|
|
|
|
// Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt
|
|
|
|
return QString("SSL_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0063:
|
|
|
|
// Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt
|
|
|
|
return QString("SSL_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0064:
|
|
|
|
// Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt
|
|
|
|
return QString("SSL_CK_RSA_EXPORT1024_WITH_RC4_56_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0065:
|
|
|
|
// Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt
|
|
|
|
return QString("SSL_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA");
|
|
|
|
break;
|
|
|
|
case 0x0066:
|
|
|
|
// Apparently from draft-ietf-tls-56-bit-ciphersuites-01.txt
|
|
|
|
return QString("SSL_CK_DHE_DSS_WITH_RC4_128_SHA");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return QString("SSL3 to be added: %1").arg(cipherID & 0xffff, 0, 16);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (TLS::SSL_v2 == version) {
|
|
|
|
switch( cipherID & 0xffffff) {
|
|
|
|
case 0x010080:
|
|
|
|
// From the Netscape SSL2 Draft Section C.4 (nov 1994)
|
|
|
|
return QString("SSL_CK_RC4_128_WITH_MD5");
|
|
|
|
break;
|
|
|
|
case 0x020080:
|
|
|
|
// From the Netscape SSL2 Draft Section C.4 (nov 1994)
|
|
|
|
return QString("SSL_CK_RC4_128_EXPORT40_WITH_MD5");
|
|
|
|
break;
|
|
|
|
case 0x030080:
|
|
|
|
// From the Netscape SSL2 Draft Section C.4 (nov 1994)
|
|
|
|
return QString("SSL_CK_RC2_128_CBC_WITH_MD5");
|
|
|
|
break;
|
|
|
|
case 0x040080:
|
|
|
|
// From the Netscape SSL2 Draft Section C.4 (nov 1994)
|
|
|
|
return QString("SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5");
|
|
|
|
break;
|
|
|
|
case 0x050080:
|
|
|
|
// From the Netscape SSL2 Draft Section C.4 (nov 1994)
|
|
|
|
return QString("SSL_CK_RC4_128_EXPORT40_WITH_MD5");
|
|
|
|
break;
|
|
|
|
case 0x060040:
|
|
|
|
// From the Netscape SSL2 Draft Section C.4 (nov 1994)
|
|
|
|
return QString("SSL_CK_DES_64_CBC_WITH_MD5");
|
|
|
|
break;
|
|
|
|
case 0x0700C0:
|
|
|
|
// From the Netscape SSL2 Draft Section C.4 (nov 1994)
|
|
|
|
return QString("SSL_CK_DES_192_EDE3_CBC_WITH_MD5");
|
|
|
|
break;
|
|
|
|
case 0x080080:
|
|
|
|
// From the openssl source, which says "MS hack"
|
|
|
|
return QString("SSL_CK_RC4_64_WITH_MD5");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return QString("SSL2 to be added: %1").arg(cipherID & 0xffffff, 0, 16);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return QString("Unknown version!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-05 08:49:15 +00:00
|
|
|
// TODO: test to ensure there is no cert-test lag
|
2005-04-22 12:46:55 +00:00
|
|
|
static bool ssl_init = false;
|
2005-07-07 00:54:12 +00:00
|
|
|
class MyTLSContext : public TLSContext
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
public:
|
2005-04-22 12:46:55 +00:00
|
|
|
enum { Good, TryAgain, Bad };
|
|
|
|
enum { Idle, Connect, Accept, Handshake, Active, Closing };
|
|
|
|
|
|
|
|
bool serv;
|
|
|
|
int mode;
|
2005-06-24 23:41:25 +00:00
|
|
|
QByteArray sendQueue;
|
|
|
|
QByteArray recvQueue;
|
2005-04-22 12:46:55 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
CertificateCollection trusted;
|
|
|
|
Certificate cert, peercert; // TODO: support cert chains
|
|
|
|
PrivateKey key;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-08-01 03:41:38 +00:00
|
|
|
Result result_result;
|
2005-07-28 12:26:55 +00:00
|
|
|
QByteArray result_to_net;
|
|
|
|
int result_encoded;
|
|
|
|
QByteArray result_plain;
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
SSL *ssl;
|
|
|
|
SSL_METHOD *method;
|
|
|
|
SSL_CTX *context;
|
|
|
|
BIO *rbio, *wbio;
|
2005-07-07 00:54:12 +00:00
|
|
|
Validity vr;
|
2005-04-22 12:46:55 +00:00
|
|
|
bool v_eof;
|
|
|
|
|
2005-08-01 03:41:38 +00:00
|
|
|
MyTLSContext(Provider *p) : TLSContext(p, "tls")
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
if(!ssl_init)
|
|
|
|
{
|
|
|
|
SSL_library_init();
|
|
|
|
SSL_load_error_strings();
|
|
|
|
ssl_init = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssl = 0;
|
|
|
|
context = 0;
|
|
|
|
reset();
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
~MyTLSContext()
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
reset();
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider::Context *clone() const
|
2005-04-22 12:46:55 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
virtual void reset()
|
|
|
|
{
|
|
|
|
if(ssl)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
SSL_free(ssl);
|
|
|
|
ssl = 0;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
2005-04-22 12:46:55 +00:00
|
|
|
if(context)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
SSL_CTX_free(context);
|
|
|
|
context = 0;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
2005-04-22 12:46:55 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
cert = Certificate();
|
|
|
|
key = PrivateKey();
|
2005-04-22 12:46:55 +00:00
|
|
|
|
|
|
|
sendQueue.resize(0);
|
|
|
|
recvQueue.resize(0);
|
|
|
|
mode = Idle;
|
2005-07-07 00:54:12 +00:00
|
|
|
peercert = Certificate();
|
|
|
|
vr = ErrorValidityUnknown;
|
2005-04-22 12:46:55 +00:00
|
|
|
v_eof = false;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2006-03-18 05:11:43 +00:00
|
|
|
virtual QStringList supportedCipherSuites(const TLS::Version &version) const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2006-03-14 04:21:52 +00:00
|
|
|
OpenSSL_add_ssl_algorithms();
|
2006-03-18 05:11:43 +00:00
|
|
|
SSL_CTX *ctx = 0;
|
|
|
|
switch (version) {
|
|
|
|
case TLS::SSL_v2:
|
|
|
|
ctx = SSL_CTX_new(SSLv2_client_method());
|
|
|
|
break;
|
|
|
|
case TLS::SSL_v3:
|
|
|
|
ctx = SSL_CTX_new(SSLv3_client_method());
|
|
|
|
break;
|
|
|
|
case TLS::TLS_v1:
|
|
|
|
ctx = SSL_CTX_new(TLSv1_client_method());
|
|
|
|
break;
|
|
|
|
case TLS::DTLS_v1:
|
|
|
|
default:
|
|
|
|
/* should not happen - should be in a "dtls" provider*/
|
|
|
|
qWarning("Unexpected enum in cipherSuites");
|
|
|
|
ctx = 0;
|
|
|
|
}
|
2006-03-14 04:21:52 +00:00
|
|
|
if (NULL == ctx)
|
|
|
|
return QStringList();
|
|
|
|
|
|
|
|
SSL *ssl = SSL_new(ctx);
|
2006-03-18 05:11:43 +00:00
|
|
|
if (NULL == ssl) {
|
|
|
|
SSL_CTX_free(ctx);
|
2006-03-14 04:21:52 +00:00
|
|
|
return QStringList();
|
2006-03-18 05:11:43 +00:00
|
|
|
}
|
2006-03-14 04:21:52 +00:00
|
|
|
|
|
|
|
STACK_OF(SSL_CIPHER) *sk = SSL_get_ciphers(ssl);
|
|
|
|
QStringList cipherList;
|
|
|
|
for(int i = 0; i < sk_SSL_CIPHER_num(sk); ++i) {
|
|
|
|
SSL_CIPHER *thisCipher = sk_SSL_CIPHER_value(sk, i);
|
2006-03-18 05:11:43 +00:00
|
|
|
cipherList += cipherIDtoString(version, thisCipher->id);
|
2006-03-14 04:21:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SSL_free(ssl);
|
|
|
|
SSL_CTX_free(ctx);
|
|
|
|
|
|
|
|
return cipherList;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
virtual bool canCompress() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
// TODO
|
|
|
|
return false;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-04-24 19:09:06 +00:00
|
|
|
virtual int maxSSF() const
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
return 256;
|
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
virtual void setConstraints(int minSSF, int maxSSF)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
// TODO
|
|
|
|
Q_UNUSED(minSSF);
|
|
|
|
Q_UNUSED(maxSSF);
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
virtual void setConstraints(const QStringList &cipherSuiteList)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
// TODO
|
|
|
|
Q_UNUSED(cipherSuiteList);
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-08-01 03:41:38 +00:00
|
|
|
virtual void setup(const CertificateCollection &_trusted, const CertificateChain &_cert, const PrivateKey &_key, bool serverMode, bool compress, bool)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
trusted = _trusted;
|
2005-04-24 19:09:06 +00:00
|
|
|
if(!_cert.isEmpty())
|
|
|
|
cert = _cert.primary(); // TODO: take the whole chain
|
2005-04-22 12:46:55 +00:00
|
|
|
key = _key;
|
2005-08-01 03:41:38 +00:00
|
|
|
serv = serverMode;
|
2005-04-22 12:46:55 +00:00
|
|
|
Q_UNUSED(compress); // TODO
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-08-01 03:41:38 +00:00
|
|
|
virtual void shutdown()
|
2005-07-28 12:26:55 +00:00
|
|
|
{
|
2005-08-01 03:41:38 +00:00
|
|
|
mode = Closing;
|
2005-07-28 12:26:55 +00:00
|
|
|
}
|
|
|
|
|
2005-08-01 03:41:38 +00:00
|
|
|
virtual void start()
|
2005-07-28 12:26:55 +00:00
|
|
|
{
|
2005-08-01 03:41:38 +00:00
|
|
|
bool ok;
|
|
|
|
if(serv)
|
|
|
|
ok = priv_startServer();
|
|
|
|
else
|
|
|
|
ok = priv_startClient();
|
|
|
|
result_result = ok ? Success : Error;
|
2005-07-28 12:26:55 +00:00
|
|
|
}
|
|
|
|
|
2005-08-01 03:41:38 +00:00
|
|
|
virtual void update(const QByteArray &from_net, const QByteArray &from_app)
|
2005-07-28 12:26:55 +00:00
|
|
|
{
|
2005-08-01 03:41:38 +00:00
|
|
|
if(mode == Active)
|
|
|
|
{
|
|
|
|
bool ok;
|
|
|
|
if(!from_app.isEmpty())
|
|
|
|
ok = priv_encode(from_app, &result_to_net, &result_encoded);
|
|
|
|
else
|
|
|
|
ok = priv_decode(from_net, &result_plain, &result_to_net);
|
|
|
|
result_result = ok ? Success : Error;
|
|
|
|
}
|
|
|
|
else if(mode == Closing)
|
|
|
|
result_result = priv_shutdown(from_net, &result_to_net);
|
|
|
|
else
|
|
|
|
result_result = priv_handshake(from_net, &result_to_net);
|
2005-07-28 12:26:55 +00:00
|
|
|
|
2005-08-01 03:41:38 +00:00
|
|
|
//printf("update (from_net=%d, to_net=%d, from_app=%d, to_app=%d)\n", from_net.size(), result_to_net.size(), from_app.size(), result_plain.size());
|
2005-07-28 12:26:55 +00:00
|
|
|
|
|
|
|
doResultsReady();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool priv_startClient()
|
2005-04-22 12:46:55 +00:00
|
|
|
{
|
2005-08-01 03:41:38 +00:00
|
|
|
//serv = false;
|
2005-04-22 12:46:55 +00:00
|
|
|
method = SSLv23_client_method();
|
|
|
|
if(!init())
|
|
|
|
return false;
|
|
|
|
mode = Connect;
|
|
|
|
return true;
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-28 12:26:55 +00:00
|
|
|
bool priv_startServer()
|
2005-04-22 12:46:55 +00:00
|
|
|
{
|
2005-08-01 03:41:38 +00:00
|
|
|
//serv = true;
|
2005-04-22 12:46:55 +00:00
|
|
|
method = SSLv23_server_method();
|
|
|
|
if(!init())
|
|
|
|
return false;
|
|
|
|
mode = Accept;
|
|
|
|
return true;
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-28 12:26:55 +00:00
|
|
|
Result priv_handshake(const QByteArray &from_net, QByteArray *to_net)
|
2005-04-22 12:46:55 +00:00
|
|
|
{
|
|
|
|
if(!from_net.isEmpty())
|
|
|
|
BIO_write(rbio, from_net.data(), from_net.size());
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
if(mode == Connect)
|
|
|
|
{
|
|
|
|
int ret = doConnect();
|
|
|
|
if(ret == Good)
|
|
|
|
{
|
|
|
|
mode = Handshake;
|
|
|
|
}
|
|
|
|
else if(ret == Bad)
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
return Error;
|
|
|
|
}
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
if(mode == Accept)
|
|
|
|
{
|
|
|
|
int ret = doAccept();
|
|
|
|
if(ret == Good)
|
|
|
|
{
|
|
|
|
getCert();
|
|
|
|
mode = Active;
|
|
|
|
}
|
|
|
|
else if(ret == Bad)
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
return Error;
|
|
|
|
}
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
if(mode == Handshake)
|
|
|
|
{
|
|
|
|
int ret = doHandshake();
|
|
|
|
if(ret == Good)
|
|
|
|
{
|
|
|
|
getCert();
|
|
|
|
mode = Active;
|
|
|
|
}
|
|
|
|
else if(ret == Bad)
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
return Error;
|
|
|
|
}
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
// process outgoing
|
|
|
|
*to_net = readOutgoing();
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
if(mode == Active)
|
|
|
|
return Success;
|
|
|
|
else
|
|
|
|
return Continue;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-28 12:26:55 +00:00
|
|
|
Result priv_shutdown(const QByteArray &from_net, QByteArray *to_net)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
if(!from_net.isEmpty())
|
|
|
|
BIO_write(rbio, from_net.data(), from_net.size());
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
int ret = doShutdown();
|
|
|
|
if(ret == Bad)
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
reset();
|
|
|
|
return Error;
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
*to_net = readOutgoing();
|
|
|
|
|
|
|
|
if(ret == Good)
|
|
|
|
{
|
|
|
|
mode = Idle;
|
|
|
|
return Success;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
2005-04-22 12:46:55 +00:00
|
|
|
else
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-08-01 03:41:38 +00:00
|
|
|
//mode = Closing;
|
2005-04-22 12:46:55 +00:00
|
|
|
return Continue;
|
|
|
|
}
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-28 12:26:55 +00:00
|
|
|
bool priv_encode(const QByteArray &plain, QByteArray *to_net, int *enc)
|
2005-04-22 12:46:55 +00:00
|
|
|
{
|
|
|
|
if(mode != Active)
|
|
|
|
return false;
|
|
|
|
sendQueue.append(plain);
|
|
|
|
|
|
|
|
int encoded = 0;
|
|
|
|
if(sendQueue.size() > 0)
|
|
|
|
{
|
|
|
|
int ret = SSL_write(ssl, sendQueue.data(), sendQueue.size());
|
|
|
|
|
|
|
|
enum { Good, Continue, Done, Error };
|
|
|
|
int m;
|
|
|
|
if(ret <= 0)
|
|
|
|
{
|
|
|
|
int x = SSL_get_error(ssl, ret);
|
|
|
|
if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
|
|
|
|
m = Continue;
|
|
|
|
else if(x == SSL_ERROR_ZERO_RETURN)
|
|
|
|
m = Done;
|
|
|
|
else
|
|
|
|
m = Error;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m = Good;
|
|
|
|
encoded = ret;
|
|
|
|
int newsize = sendQueue.size() - encoded;
|
|
|
|
char *r = sendQueue.data();
|
|
|
|
memmove(r, r + encoded, newsize);
|
|
|
|
sendQueue.resize(newsize);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m == Done)
|
|
|
|
{
|
|
|
|
sendQueue.resize(0);
|
|
|
|
v_eof = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(m == Error)
|
|
|
|
{
|
|
|
|
sendQueue.resize(0);
|
|
|
|
return false;
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
*to_net = readOutgoing();
|
|
|
|
*enc = encoded;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-07-28 12:26:55 +00:00
|
|
|
bool priv_decode(const QByteArray &from_net, QByteArray *plain, QByteArray *to_net)
|
2005-04-22 12:46:55 +00:00
|
|
|
{
|
|
|
|
if(mode != Active)
|
|
|
|
return false;
|
|
|
|
if(!from_net.isEmpty())
|
|
|
|
BIO_write(rbio, from_net.data(), from_net.size());
|
|
|
|
|
|
|
|
QByteArray a;
|
|
|
|
while(!v_eof) {
|
|
|
|
a.resize(8192);
|
|
|
|
int ret = SSL_read(ssl, a.data(), a.size());
|
2005-08-01 03:41:38 +00:00
|
|
|
//printf("SSL_read = %d\n", ret);
|
2005-04-22 12:46:55 +00:00
|
|
|
if(ret > 0)
|
|
|
|
{
|
|
|
|
if(ret != (int)a.size())
|
|
|
|
a.resize(ret);
|
2005-08-01 03:41:38 +00:00
|
|
|
//printf("SSL_read chunk: [%s]\n", qPrintable(arrayToHex(a)));
|
2005-04-22 12:46:55 +00:00
|
|
|
recvQueue.append(a);
|
|
|
|
}
|
|
|
|
else if(ret <= 0)
|
|
|
|
{
|
2005-08-01 03:41:38 +00:00
|
|
|
ERR_print_errors_fp(stdout);
|
2005-04-22 12:46:55 +00:00
|
|
|
int x = SSL_get_error(ssl, ret);
|
2005-08-01 03:41:38 +00:00
|
|
|
//printf("SSL_read error = %d\n", x);
|
2005-04-22 12:46:55 +00:00
|
|
|
if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
|
|
|
|
break;
|
|
|
|
else if(x == SSL_ERROR_ZERO_RETURN)
|
|
|
|
v_eof = true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*plain = recvQueue;
|
|
|
|
recvQueue.resize(0);
|
|
|
|
|
|
|
|
// could be outgoing data also
|
|
|
|
*to_net = readOutgoing();
|
|
|
|
return true;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-28 12:26:55 +00:00
|
|
|
virtual void waitForResultsReady(int msecs)
|
|
|
|
{
|
|
|
|
// TODO: for now, all operations block anyway
|
|
|
|
Q_UNUSED(msecs);
|
|
|
|
}
|
|
|
|
|
2005-08-01 03:41:38 +00:00
|
|
|
virtual Result result() const
|
2005-07-28 12:26:55 +00:00
|
|
|
{
|
2005-08-01 03:41:38 +00:00
|
|
|
return result_result;
|
2005-07-28 12:26:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual QByteArray to_net()
|
|
|
|
{
|
|
|
|
QByteArray a = result_to_net;
|
|
|
|
result_to_net.clear();
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual int encoded() const
|
|
|
|
{
|
|
|
|
return result_encoded;
|
|
|
|
}
|
|
|
|
|
2005-08-01 03:41:38 +00:00
|
|
|
virtual QByteArray to_app()
|
2005-07-28 12:26:55 +00:00
|
|
|
{
|
|
|
|
QByteArray a = result_plain;
|
|
|
|
result_plain.clear();
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
virtual bool eof() const
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
return v_eof;
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
virtual SessionInfo sessionInfo() const
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
return SessionInfo();
|
|
|
|
}
|
|
|
|
|
2005-04-24 19:09:06 +00:00
|
|
|
virtual QByteArray unprocessed()
|
2005-04-22 12:46:55 +00:00
|
|
|
{
|
2005-04-24 19:09:06 +00:00
|
|
|
QByteArray a;
|
2005-04-22 12:46:55 +00:00
|
|
|
int size = BIO_pending(rbio);
|
|
|
|
if(size <= 0)
|
|
|
|
return a;
|
|
|
|
a.resize(size);
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
int r = BIO_read(rbio, a.data(), size);
|
|
|
|
if(r <= 0)
|
|
|
|
{
|
|
|
|
a.resize(0);
|
|
|
|
return a;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
2005-04-22 12:46:55 +00:00
|
|
|
if(r != size)
|
|
|
|
a.resize(r);
|
|
|
|
return a;
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Validity peerCertificateValidity() const
|
2005-04-22 12:46:55 +00:00
|
|
|
{
|
|
|
|
return vr;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual CertificateChain peerCertificateChain() const
|
2005-04-22 12:46:55 +00:00
|
|
|
{
|
|
|
|
// TODO: support whole chain
|
2005-07-07 00:54:12 +00:00
|
|
|
CertificateChain chain;
|
2005-04-22 12:46:55 +00:00
|
|
|
chain.append(peercert);
|
|
|
|
return chain;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-07-28 12:26:55 +00:00
|
|
|
void doResultsReady()
|
|
|
|
{
|
|
|
|
QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection);
|
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
bool init()
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
context = SSL_CTX_new(method);
|
|
|
|
if(!context)
|
|
|
|
return false;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-23 04:40:11 +00:00
|
|
|
// setup the cert store
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
X509_STORE *store = SSL_CTX_get_cert_store(context);
|
2005-07-07 00:54:12 +00:00
|
|
|
QList<Certificate> cert_list = trusted.certificates();
|
|
|
|
QList<CRL> crl_list = trusted.crls();
|
2005-04-23 04:40:11 +00:00
|
|
|
int n;
|
|
|
|
for(n = 0; n < cert_list.count(); ++n)
|
|
|
|
{
|
|
|
|
const MyCertContext *cc = static_cast<const MyCertContext *>(cert_list[n].context());
|
|
|
|
X509 *x = cc->item.cert;
|
|
|
|
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
|
|
|
|
X509_STORE_add_cert(store, x);
|
|
|
|
}
|
|
|
|
for(n = 0; n < crl_list.count(); ++n)
|
|
|
|
{
|
|
|
|
const MyCRLContext *cc = static_cast<const MyCRLContext *>(crl_list[n].context());
|
|
|
|
X509_CRL *x = cc->item.crl;
|
|
|
|
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL);
|
|
|
|
X509_STORE_add_crl(store, x);
|
|
|
|
}
|
|
|
|
}
|
2005-04-22 12:46:55 +00:00
|
|
|
|
|
|
|
ssl = SSL_new(context);
|
|
|
|
if(!ssl)
|
|
|
|
{
|
|
|
|
SSL_CTX_free(context);
|
|
|
|
context = 0;
|
|
|
|
return false;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
2005-04-22 12:46:55 +00:00
|
|
|
SSL_set_ssl_method(ssl, method); // can this return error?
|
|
|
|
|
|
|
|
// setup the memory bio
|
|
|
|
rbio = BIO_new(BIO_s_mem());
|
|
|
|
wbio = BIO_new(BIO_s_mem());
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
// this passes control of the bios to ssl. we don't need to free them.
|
|
|
|
SSL_set_bio(ssl, rbio, wbio);
|
|
|
|
|
|
|
|
// setup the cert to send
|
|
|
|
if(!cert.isNull() && !key.isNull())
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-28 12:26:55 +00:00
|
|
|
PrivateKey nkey = key;
|
|
|
|
|
|
|
|
const PKeyContext *tmp_kc = static_cast<const PKeyContext *>(nkey.context());
|
|
|
|
|
|
|
|
if(!tmp_kc->sameProvider(this))
|
|
|
|
{
|
|
|
|
printf("experimental: private key supplied by a different provider\n");
|
|
|
|
|
|
|
|
// make a pkey pointing to the existing private key
|
|
|
|
EVP_PKEY *pkey;
|
|
|
|
pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_RSA(pkey, createFromExisting(nkey.toRSA()));
|
|
|
|
|
|
|
|
// make a new private key object to hold it
|
|
|
|
MyPKeyContext *pk = new MyPKeyContext(provider());
|
|
|
|
PKeyBase *k = pk->pkeyToBase(pkey, true); // does an EVP_PKEY_free()
|
|
|
|
pk->k = k;
|
|
|
|
nkey.change(pk);
|
|
|
|
}
|
|
|
|
|
|
|
|
const MyCertContext *cc = static_cast<const MyCertContext *>(cert.context());
|
|
|
|
const MyPKeyContext *kc = static_cast<const MyPKeyContext *>(nkey.context());
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
if(SSL_use_certificate(ssl, cc->item.cert) != 1)
|
|
|
|
{
|
|
|
|
SSL_free(ssl);
|
|
|
|
SSL_CTX_free(context);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(SSL_use_PrivateKey(ssl, kc->get_pkey()) != 1)
|
|
|
|
{
|
|
|
|
SSL_free(ssl);
|
|
|
|
SSL_CTX_free(context);
|
|
|
|
return false;
|
|
|
|
}
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void getCert()
|
|
|
|
{
|
|
|
|
// verify the certificate
|
2005-07-07 00:54:12 +00:00
|
|
|
Validity code = ErrorValidityUnknown;
|
2005-04-22 12:46:55 +00:00
|
|
|
X509 *x = SSL_get_peer_certificate(ssl);
|
|
|
|
if(x)
|
|
|
|
{
|
|
|
|
MyCertContext *cc = new MyCertContext(provider());
|
|
|
|
cc->fromX509(x);
|
|
|
|
X509_free(x);
|
|
|
|
peercert.change(cc);
|
|
|
|
|
|
|
|
int ret = SSL_get_verify_result(ssl);
|
|
|
|
if(ret == X509_V_OK)
|
2005-07-07 00:54:12 +00:00
|
|
|
code = ValidityGood;
|
2005-04-22 12:46:55 +00:00
|
|
|
else
|
|
|
|
code = convert_verify_error(ret);
|
|
|
|
}
|
|
|
|
else
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
peercert = Certificate();
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
2005-04-22 12:46:55 +00:00
|
|
|
vr = code;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
int doConnect()
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
int ret = SSL_connect(ssl);
|
|
|
|
if(ret < 0)
|
|
|
|
{
|
|
|
|
int x = SSL_get_error(ssl, ret);
|
|
|
|
if(x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
|
|
|
|
return TryAgain;
|
|
|
|
else
|
|
|
|
return Bad;
|
|
|
|
}
|
|
|
|
else if(ret == 0)
|
|
|
|
return Bad;
|
|
|
|
return Good;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
int doAccept()
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
int ret = SSL_accept(ssl);
|
|
|
|
if(ret < 0)
|
|
|
|
{
|
|
|
|
int x = SSL_get_error(ssl, ret);
|
|
|
|
if(x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
|
|
|
|
return TryAgain;
|
|
|
|
else
|
|
|
|
return Bad;
|
|
|
|
}
|
|
|
|
else if(ret == 0)
|
|
|
|
return Bad;
|
|
|
|
return Good;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
int doHandshake()
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
int ret = SSL_do_handshake(ssl);
|
|
|
|
if(ret < 0)
|
|
|
|
{
|
|
|
|
int x = SSL_get_error(ssl, ret);
|
|
|
|
if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
|
|
|
|
return TryAgain;
|
|
|
|
else
|
|
|
|
return Bad;
|
|
|
|
}
|
|
|
|
else if(ret == 0)
|
|
|
|
return Bad;
|
|
|
|
return Good;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
|
|
|
|
2005-04-22 12:46:55 +00:00
|
|
|
int doShutdown()
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
2005-04-22 12:46:55 +00:00
|
|
|
int ret = SSL_shutdown(ssl);
|
|
|
|
if(ret >= 1)
|
|
|
|
return Good;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(ret == 0)
|
|
|
|
return TryAgain;
|
|
|
|
int x = SSL_get_error(ssl, ret);
|
|
|
|
if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
|
|
|
|
return TryAgain;
|
|
|
|
return Bad;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray readOutgoing()
|
|
|
|
{
|
|
|
|
QByteArray a;
|
|
|
|
int size = BIO_pending(wbio);
|
|
|
|
if(size <= 0)
|
|
|
|
return a;
|
|
|
|
a.resize(size);
|
|
|
|
|
|
|
|
int r = BIO_read(wbio, a.data(), size);
|
|
|
|
if(r <= 0)
|
|
|
|
{
|
|
|
|
a.resize(0);
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
if(r != size)
|
|
|
|
a.resize(r);
|
|
|
|
return a;
|
2005-03-14 11:38:23 +00:00
|
|
|
}
|
2005-04-22 12:46:55 +00:00
|
|
|
};
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
class CMSContext : public SMSContext
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
public:
|
2005-07-07 00:54:12 +00:00
|
|
|
CertificateCollection trustedCerts;
|
|
|
|
QList<SecureMessageKey> privateKeys;
|
2005-06-25 20:27:10 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
CMSContext(Provider *p) : SMSContext(p, "cms")
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~CMSContext()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider::Context *clone() const
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void setTrustedCertificates(const CertificateCollection &trusted)
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
2005-06-25 20:27:10 +00:00
|
|
|
trustedCerts = trusted;
|
2005-05-10 21:10:35 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void setPrivateKeys(const QList<SecureMessageKey> &keys)
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
2005-06-25 20:27:10 +00:00
|
|
|
privateKeys = keys;
|
2005-05-10 21:10:35 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual MessageContext *createMessage();
|
2005-05-10 21:10:35 +00:00
|
|
|
};
|
|
|
|
|
2005-06-25 20:27:10 +00:00
|
|
|
STACK_OF(X509) *get_pk7_certs(PKCS7 *p7)
|
|
|
|
{
|
|
|
|
int i = OBJ_obj2nid(p7->type);
|
|
|
|
if(i == NID_pkcs7_signed)
|
|
|
|
return p7->d.sign->cert;
|
|
|
|
else if(i == NID_pkcs7_signedAndEnveloped)
|
|
|
|
return p7->d.signed_and_enveloped->cert;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
class MyMessageContext : public MessageContext
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
2005-06-25 20:27:10 +00:00
|
|
|
CMSContext *cms;
|
2005-07-07 00:54:12 +00:00
|
|
|
SecureMessageKey signer;
|
|
|
|
SecureMessageKeyList to;
|
|
|
|
SecureMessage::SignMode signMode;
|
2005-05-10 21:10:35 +00:00
|
|
|
bool bundleSigner;
|
|
|
|
bool smime;
|
2005-07-07 00:54:12 +00:00
|
|
|
SecureMessage::Format format;
|
2005-05-10 21:10:35 +00:00
|
|
|
|
|
|
|
Operation op;
|
|
|
|
|
2005-06-24 23:41:25 +00:00
|
|
|
QByteArray in, out;
|
|
|
|
QByteArray sig;
|
2005-05-10 21:10:35 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
CertificateChain signerChain;
|
2005-06-25 20:27:10 +00:00
|
|
|
int ver_ret;
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
MyMessageContext(CMSContext *_cms, Provider *p) : MessageContext(p, "cmsmsg")
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
2005-06-25 20:27:10 +00:00
|
|
|
cms = _cms;
|
|
|
|
|
|
|
|
ver_ret = 0;
|
2005-05-10 21:10:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
~MyMessageContext()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider::Context *clone() const
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool canSignMultiple() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual SecureMessage::Type type() const
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
return SecureMessage::CMS;
|
2005-05-10 21:10:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void reset()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void setupEncrypt(const SecureMessageKeyList &keys)
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
to = keys;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void setupSign(const SecureMessageKeyList &keys, SecureMessage::SignMode m, bool bundleSigner, bool smime)
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
signer = keys.first();
|
|
|
|
signMode = m;
|
|
|
|
this->bundleSigner = bundleSigner;
|
|
|
|
this->smime = smime;
|
|
|
|
}
|
|
|
|
|
2005-06-24 23:41:25 +00:00
|
|
|
virtual void setupVerify(const QByteArray &detachedSig)
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
// TODO
|
2005-06-25 20:27:10 +00:00
|
|
|
sig = detachedSig;
|
2005-05-10 21:10:35 +00:00
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual void start(SecureMessage::Format f, Operation op)
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
format = f;
|
|
|
|
|
|
|
|
// TODO: other operations
|
2005-06-25 20:27:10 +00:00
|
|
|
//if(op == Sign)
|
|
|
|
//{
|
2005-05-10 21:10:35 +00:00
|
|
|
this->op = op;
|
2005-06-25 20:27:10 +00:00
|
|
|
//}
|
|
|
|
//else if(op == Encrypt)
|
|
|
|
//{
|
|
|
|
// this->op = op;
|
|
|
|
//}
|
2005-05-10 21:10:35 +00:00
|
|
|
}
|
|
|
|
|
2005-06-24 23:41:25 +00:00
|
|
|
virtual void update(const QByteArray &in)
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
this->in.append(in);
|
|
|
|
}
|
|
|
|
|
2005-06-24 23:41:25 +00:00
|
|
|
virtual QByteArray read()
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void end()
|
|
|
|
{
|
|
|
|
// sign
|
|
|
|
if(op == Sign)
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
CertificateChain chain = signer.x509CertificateChain();
|
|
|
|
Certificate cert = chain.primary();
|
|
|
|
QList<Certificate> nonroots;
|
2005-05-10 21:10:35 +00:00
|
|
|
if(chain.count() > 1)
|
|
|
|
{
|
|
|
|
for(int n = 1; n < chain.count(); ++n)
|
|
|
|
nonroots.append(chain[n]);
|
|
|
|
}
|
2005-07-07 00:54:12 +00:00
|
|
|
PrivateKey key = signer.x509PrivateKey();
|
2005-05-10 21:10:35 +00:00
|
|
|
|
2005-07-28 12:26:55 +00:00
|
|
|
const PKeyContext *tmp_kc = static_cast<const PKeyContext *>(key.context());
|
|
|
|
|
|
|
|
if(!tmp_kc->sameProvider(this))
|
|
|
|
{
|
|
|
|
printf("experimental: private key supplied by a different provider\n");
|
|
|
|
|
|
|
|
// make a pkey pointing to the existing private key
|
|
|
|
EVP_PKEY *pkey;
|
|
|
|
pkey = EVP_PKEY_new();
|
|
|
|
EVP_PKEY_assign_RSA(pkey, createFromExisting(key.toRSA()));
|
|
|
|
|
|
|
|
// make a new private key object to hold it
|
|
|
|
MyPKeyContext *pk = new MyPKeyContext(provider());
|
|
|
|
PKeyBase *k = pk->pkeyToBase(pkey, true); // does an EVP_PKEY_free()
|
|
|
|
pk->k = k;
|
|
|
|
key.change(pk);
|
|
|
|
}
|
|
|
|
|
2005-05-10 21:10:35 +00:00
|
|
|
MyCertContext *cc = static_cast<MyCertContext *>(cert.context());
|
|
|
|
MyPKeyContext *kc = static_cast<MyPKeyContext *>(key.context());
|
|
|
|
|
|
|
|
X509 *cx = cc->item.cert;
|
|
|
|
EVP_PKEY *kx = kc->get_pkey();
|
|
|
|
|
|
|
|
STACK_OF(X509) *other_certs;
|
|
|
|
BIO *bi;
|
|
|
|
int flags;
|
|
|
|
PKCS7 *p7;
|
|
|
|
|
|
|
|
// nonroots
|
|
|
|
other_certs = sk_X509_new_null();
|
|
|
|
for(int n = 0; n < nonroots.count(); ++n)
|
|
|
|
{
|
|
|
|
X509 *x = static_cast<MyCertContext *>(nonroots[n].context())->item.cert;
|
|
|
|
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
|
|
|
|
sk_X509_push(other_certs, x);
|
|
|
|
}
|
|
|
|
|
2005-06-25 20:27:10 +00:00
|
|
|
//printf("bundling %d other_certs\n", sk_X509_num(other_certs));
|
|
|
|
|
2005-05-10 21:10:35 +00:00
|
|
|
bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, in.data(), in.size());
|
|
|
|
|
|
|
|
flags = 0;
|
|
|
|
flags |= PKCS7_BINARY;
|
|
|
|
flags |= PKCS7_DETACHED; // FIXME: signmode
|
|
|
|
//flags |= PKCS7_NOCERTS; // FIXME: bundleSigner
|
|
|
|
p7 = PKCS7_sign(cx, kx, other_certs, bi, flags);
|
|
|
|
|
|
|
|
BIO_free(bi);
|
|
|
|
sk_X509_pop_free(other_certs, X509_free);
|
|
|
|
|
|
|
|
if(p7)
|
|
|
|
{
|
|
|
|
//printf("good\n");
|
|
|
|
BIO *bo;
|
|
|
|
|
|
|
|
//BIO *bo = BIO_new(BIO_s_mem());
|
|
|
|
//i2d_PKCS7_bio(bo, p7);
|
|
|
|
//PEM_write_bio_PKCS7(bo, p7);
|
|
|
|
//QSecureArray buf = bio2buf(bo);
|
|
|
|
//printf("[%s]\n", buf.data());
|
|
|
|
|
|
|
|
// FIXME: format
|
|
|
|
bo = BIO_new(BIO_s_mem());
|
|
|
|
i2d_PKCS7_bio(bo, p7);
|
2005-06-24 23:41:25 +00:00
|
|
|
sig = bio2ba(bo);
|
2005-05-10 21:10:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-07-28 12:26:55 +00:00
|
|
|
printf("bad here\n");
|
|
|
|
ERR_print_errors_fp(stdout);
|
2005-05-10 21:10:35 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(op == Encrypt)
|
|
|
|
{
|
|
|
|
// TODO: support multiple recipients
|
2005-07-07 00:54:12 +00:00
|
|
|
Certificate target = to.first().x509CertificateChain().primary();
|
2005-05-10 21:10:35 +00:00
|
|
|
|
|
|
|
STACK_OF(X509) *other_certs;
|
|
|
|
BIO *bi;
|
|
|
|
int flags;
|
|
|
|
PKCS7 *p7;
|
|
|
|
|
|
|
|
other_certs = sk_X509_new_null();
|
|
|
|
X509 *x = static_cast<MyCertContext *>(target.context())->item.cert;
|
|
|
|
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
|
|
|
|
sk_X509_push(other_certs, x);
|
|
|
|
|
|
|
|
bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, in.data(), in.size());
|
|
|
|
|
|
|
|
flags = 0;
|
|
|
|
flags |= PKCS7_BINARY;
|
|
|
|
p7 = PKCS7_encrypt(other_certs, bi, EVP_des_ede3_cbc(), flags); // TODO: cipher?
|
|
|
|
|
|
|
|
BIO_free(bi);
|
|
|
|
sk_X509_pop_free(other_certs, X509_free);
|
|
|
|
|
|
|
|
QString env;
|
|
|
|
if(p7)
|
|
|
|
{
|
|
|
|
// FIXME: format
|
|
|
|
BIO *bo = BIO_new(BIO_s_mem());
|
|
|
|
i2d_PKCS7_bio(bo, p7);
|
|
|
|
//PEM_write_bio_PKCS7(bo, p7);
|
2005-06-24 23:41:25 +00:00
|
|
|
out = bio2ba(bo);
|
2005-05-10 21:10:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printf("bad\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2005-06-25 20:27:10 +00:00
|
|
|
else if(op == Verify)
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
2005-06-25 20:27:10 +00:00
|
|
|
// TODO: support non-detached sigs
|
|
|
|
|
|
|
|
BIO *bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, sig.data(), sig.size());
|
|
|
|
PKCS7 *p7 = d2i_PKCS7_bio(bi, NULL);
|
|
|
|
BIO_free(bi);
|
|
|
|
|
|
|
|
if(!p7)
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
printf("bad1\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
CertificateChain chain;
|
2005-06-25 20:27:10 +00:00
|
|
|
//STACK_OF(X509) *xs = PKCS7_get0_signers(p7, NULL, 0);
|
|
|
|
STACK_OF(X509) *xs = get_pk7_certs(p7);
|
|
|
|
if(xs)
|
|
|
|
{
|
|
|
|
// TODO: reorder in chain-order?
|
|
|
|
// TODO: throw out certs that don't fit the chain?
|
|
|
|
for(int n = 0; n < sk_X509_num(xs); ++n)
|
|
|
|
{
|
|
|
|
MyCertContext *cc = new MyCertContext(provider());
|
|
|
|
cc->fromX509(sk_X509_value(xs, n));
|
2005-07-07 00:54:12 +00:00
|
|
|
Certificate cert;
|
2005-06-25 20:27:10 +00:00
|
|
|
cert.change(cc);
|
|
|
|
chain.append(cert);
|
|
|
|
}
|
|
|
|
//sk_X509_pop_free(xs, X509_free);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!chain.isEmpty())
|
|
|
|
{
|
|
|
|
//for(int n = 0; n < chain.count(); ++n)
|
|
|
|
// printf("%d %s\n", n, qPrintable(chain[n].commonName()));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
printf("no chain\n");
|
|
|
|
|
|
|
|
signerChain = chain;
|
|
|
|
|
|
|
|
// TODO: support using a signer not stored in the signature
|
|
|
|
if(chain.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
X509_STORE *store = X509_STORE_new();
|
2005-07-07 00:54:12 +00:00
|
|
|
QList<Certificate> cert_list = cms->trustedCerts.certificates();
|
|
|
|
QList<CRL> crl_list = cms->trustedCerts.crls();
|
2005-06-25 20:27:10 +00:00
|
|
|
int n;
|
|
|
|
for(n = 0; n < cert_list.count(); ++n)
|
|
|
|
{
|
|
|
|
const MyCertContext *cc = static_cast<const MyCertContext *>(cert_list[n].context());
|
|
|
|
X509 *x = cc->item.cert;
|
|
|
|
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
|
|
|
|
X509_STORE_add_cert(store, x);
|
|
|
|
}
|
|
|
|
for(n = 0; n < crl_list.count(); ++n)
|
|
|
|
{
|
|
|
|
const MyCRLContext *cc = static_cast<const MyCRLContext *>(crl_list[n].context());
|
|
|
|
X509_CRL *x = cc->item.crl;
|
|
|
|
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL);
|
|
|
|
X509_STORE_add_crl(store, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, in.data(), in.size());
|
|
|
|
int ret = PKCS7_verify(p7, xs, store, bi, NULL, 0);
|
|
|
|
BIO_free(bi);
|
|
|
|
X509_STORE_free(store);
|
|
|
|
PKCS7_free(p7);
|
|
|
|
|
|
|
|
ver_ret = ret;
|
2005-05-10 21:10:35 +00:00
|
|
|
// TODO
|
|
|
|
}
|
2005-06-25 20:27:10 +00:00
|
|
|
else if(op == Decrypt)
|
|
|
|
{
|
|
|
|
bool ok = false;
|
|
|
|
for(int n = 0; n < cms->privateKeys.count(); ++n)
|
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
CertificateChain chain = cms->privateKeys[n].x509CertificateChain();
|
|
|
|
Certificate cert = chain.primary();
|
|
|
|
PrivateKey key = cms->privateKeys[n].x509PrivateKey();
|
2005-06-25 20:27:10 +00:00
|
|
|
|
|
|
|
MyCertContext *cc = static_cast<MyCertContext *>(cert.context());
|
|
|
|
MyPKeyContext *kc = static_cast<MyPKeyContext *>(key.context());
|
|
|
|
|
|
|
|
X509 *cx = cc->item.cert;
|
|
|
|
EVP_PKEY *kx = kc->get_pkey();
|
|
|
|
|
|
|
|
BIO *bi = BIO_new(BIO_s_mem());
|
|
|
|
BIO_write(bi, in.data(), in.size());
|
|
|
|
PKCS7 *p7 = d2i_PKCS7_bio(bi, NULL);
|
|
|
|
BIO_free(bi);
|
|
|
|
|
|
|
|
if(!p7)
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
printf("bad1\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BIO *bo = BIO_new(BIO_s_mem());
|
|
|
|
int ret = PKCS7_decrypt(p7, kx, cx, bo, 0);
|
|
|
|
PKCS7_free(p7);
|
|
|
|
if(!ret)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ok = true;
|
|
|
|
out = bio2ba(bo);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!ok)
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
printf("bad2\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2005-05-10 21:10:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool finished() const
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void waitForFinished(int msecs)
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
Q_UNUSED(msecs);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool success() const
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual SecureMessage::Error errorCode() const
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
// TODO
|
2005-07-07 00:54:12 +00:00
|
|
|
return SecureMessage::ErrorUnknown;
|
2005-05-10 21:10:35 +00:00
|
|
|
}
|
|
|
|
|
2005-06-24 23:41:25 +00:00
|
|
|
virtual QByteArray signature() const
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
|
|
|
return sig;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual QString hashName() const
|
|
|
|
{
|
2005-06-25 20:27:10 +00:00
|
|
|
// TODO
|
2005-05-10 21:10:35 +00:00
|
|
|
return "sha1";
|
|
|
|
}
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual SecureMessageSignatureList signers() const
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
2005-07-07 00:54:12 +00:00
|
|
|
SecureMessageKey key;
|
2005-06-25 20:27:10 +00:00
|
|
|
if(!signerChain.isEmpty())
|
|
|
|
key.setX509CertificateChain(signerChain);
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
SecureMessageSignature s(
|
|
|
|
ver_ret ? SecureMessageSignature::Valid : SecureMessageSignature::InvalidSignature,
|
|
|
|
ver_ret ? ValidityGood : ErrorValidityUnknown,
|
2005-06-25 20:27:10 +00:00
|
|
|
key,
|
|
|
|
QDateTime::currentDateTime());
|
|
|
|
|
2005-05-10 21:10:35 +00:00
|
|
|
// TODO
|
2005-07-07 00:54:12 +00:00
|
|
|
return SecureMessageSignatureList() << s;
|
2005-05-10 21:10:35 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
MessageContext *CMSContext::createMessage()
|
2005-05-10 21:10:35 +00:00
|
|
|
{
|
2005-06-25 20:27:10 +00:00
|
|
|
return new MyMessageContext(this, provider());
|
2005-05-10 21:10:35 +00:00
|
|
|
}
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
class opensslCipherContext : public CipherContext
|
2005-03-21 07:19:14 +00:00
|
|
|
{
|
|
|
|
public:
|
2005-07-07 00:54:12 +00:00
|
|
|
opensslCipherContext(const EVP_CIPHER *algorithm, const int pad, Provider *p, const QString &type) : CipherContext(p, type)
|
2005-03-21 07:19:14 +00:00
|
|
|
{
|
|
|
|
m_cryptoAlgorithm = algorithm;
|
|
|
|
EVP_CIPHER_CTX_init(&m_context);
|
|
|
|
m_pad = pad;
|
|
|
|
m_type = type;
|
|
|
|
}
|
|
|
|
|
2006-01-15 05:41:02 +00:00
|
|
|
~opensslCipherContext()
|
|
|
|
{
|
|
|
|
EVP_CIPHER_CTX_cleanup(&m_context);
|
|
|
|
}
|
2005-03-21 07:19:14 +00:00
|
|
|
|
2006-01-15 05:41:02 +00:00
|
|
|
void setup(Direction dir,
|
|
|
|
const SymmetricKey &key,
|
|
|
|
const InitializationVector &iv)
|
|
|
|
{
|
|
|
|
m_direction = dir;
|
|
|
|
if ( ( m_cryptoAlgorithm == EVP_des_ede3() ) && (key.size() == 16) ) {
|
|
|
|
// this is really a two key version of triple DES.
|
|
|
|
m_cryptoAlgorithm = EVP_des_ede();
|
2005-03-21 07:19:14 +00:00
|
|
|
}
|
2006-01-15 05:41:02 +00:00
|
|
|
if (Encode == m_direction) {
|
|
|
|
EVP_EncryptInit_ex(&m_context, m_cryptoAlgorithm, 0, 0, 0);
|
|
|
|
EVP_CIPHER_CTX_set_key_length(&m_context, key.size());
|
|
|
|
EVP_EncryptInit_ex(&m_context, 0, 0,
|
|
|
|
(const unsigned char*)(key.data()),
|
|
|
|
(const unsigned char*)(iv.data()));
|
|
|
|
} else {
|
|
|
|
EVP_DecryptInit_ex(&m_context, m_cryptoAlgorithm, 0, 0, 0);
|
|
|
|
EVP_CIPHER_CTX_set_key_length(&m_context, key.size());
|
|
|
|
EVP_DecryptInit_ex(&m_context, 0, 0,
|
|
|
|
(const unsigned char*)(key.data()),
|
|
|
|
(const unsigned char*)(iv.data()));
|
2005-03-21 07:19:14 +00:00
|
|
|
}
|
2006-01-15 05:41:02 +00:00
|
|
|
|
|
|
|
EVP_CIPHER_CTX_set_padding(&m_context, m_pad);
|
|
|
|
}
|
|
|
|
|
|
|
|
Provider::Context *clone() const
|
|
|
|
{
|
|
|
|
return new opensslCipherContext( *this );
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int blockSize() const
|
|
|
|
{
|
|
|
|
return EVP_CIPHER_CTX_block_size(&m_context);
|
|
|
|
}
|
2005-03-21 07:19:14 +00:00
|
|
|
|
2006-01-15 05:41:02 +00:00
|
|
|
bool update(const QSecureArray &in, QSecureArray *out)
|
|
|
|
{
|
|
|
|
// This works around a problem in OpenSSL, where it asserts if
|
|
|
|
// there is nothing to encrypt.
|
|
|
|
if ( 0 == in.size() )
|
2005-03-21 07:19:14 +00:00
|
|
|
return true;
|
|
|
|
|
2006-01-15 05:41:02 +00:00
|
|
|
out->resize(in.size()+blockSize());
|
|
|
|
int resultLength;
|
|
|
|
if (Encode == m_direction) {
|
|
|
|
if (0 == EVP_EncryptUpdate(&m_context,
|
|
|
|
(unsigned char*)out->data(),
|
|
|
|
&resultLength,
|
|
|
|
(unsigned char*)in.data(),
|
|
|
|
in.size())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (0 == EVP_DecryptUpdate(&m_context,
|
|
|
|
(unsigned char*)out->data(),
|
|
|
|
&resultLength,
|
|
|
|
(unsigned char*)in.data(),
|
|
|
|
in.size())) {
|
|
|
|
return false;
|
2005-03-21 07:19:14 +00:00
|
|
|
}
|
|
|
|
}
|
2006-01-15 05:41:02 +00:00
|
|
|
out->resize(resultLength);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool final(QSecureArray *out)
|
|
|
|
{
|
|
|
|
out->resize(blockSize());
|
|
|
|
int resultLength;
|
|
|
|
if (Encode == m_direction) {
|
|
|
|
if (0 == EVP_EncryptFinal_ex(&m_context,
|
|
|
|
(unsigned char*)out->data(),
|
|
|
|
&resultLength)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (0 == EVP_DecryptFinal_ex(&m_context,
|
|
|
|
(unsigned char*)out->data(),
|
|
|
|
&resultLength)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out->resize(resultLength);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Change cipher names
|
|
|
|
KeyLength keyLength() const
|
|
|
|
{
|
|
|
|
if (m_type.left(4) == "des-") {
|
|
|
|
return KeyLength( 8, 8, 1);
|
|
|
|
} else if (m_type.left(6) == "aes128") {
|
|
|
|
return KeyLength( 16, 16, 1);
|
|
|
|
} else if (m_type.left(6) == "aes192") {
|
|
|
|
return KeyLength( 24, 24, 1);
|
|
|
|
} else if (m_type.left(6) == "aes256") {
|
|
|
|
return KeyLength( 32, 32, 1);
|
|
|
|
} else if (m_type.left(8) == "blowfish") {
|
|
|
|
// Don't know - TODO
|
|
|
|
return KeyLength( 1, 32, 1);
|
|
|
|
} else if (m_type.left(9) == "tripledes") {
|
|
|
|
return KeyLength( 16, 24, 1);
|
|
|
|
} else {
|
|
|
|
return KeyLength( 0, 1, 1);
|
|
|
|
}
|
|
|
|
}
|
2005-03-21 07:19:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
protected:
|
2006-01-15 05:41:02 +00:00
|
|
|
EVP_CIPHER_CTX m_context;
|
|
|
|
const EVP_CIPHER *m_cryptoAlgorithm;
|
|
|
|
Direction m_direction;
|
|
|
|
int m_pad;
|
|
|
|
QString m_type;
|
2005-03-21 07:19:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
using namespace opensslQCAPlugin;
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2005-07-07 00:54:12 +00:00
|
|
|
class opensslProvider : public Provider
|
2005-03-14 11:38:23 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
void init()
|
|
|
|
{
|
|
|
|
OpenSSL_add_all_algorithms();
|
|
|
|
ERR_load_crypto_strings();
|
|
|
|
|
|
|
|
srand(time(NULL));
|
|
|
|
char buf[128];
|
|
|
|
for(int n = 0; n < 128; ++n)
|
|
|
|
buf[n] = rand();
|
|
|
|
RAND_seed(buf, 128);
|
|
|
|
}
|
|
|
|
|
|
|
|
~opensslProvider()
|
|
|
|
{
|
|
|
|
// todo: any shutdown?
|
|
|
|
}
|
|
|
|
|
|
|
|
QString name() const
|
|
|
|
{
|
|
|
|
return "qca-openssl";
|
|
|
|
}
|
|
|
|
|
2006-02-25 02:43:31 +00:00
|
|
|
QString credit() const
|
|
|
|
{
|
|
|
|
return QString(
|
|
|
|
"This product includes cryptographic software "
|
|
|
|
"written by Eric Young (eay@cryptsoft.com)");
|
|
|
|
}
|
|
|
|
|
2005-03-14 11:38:23 +00:00
|
|
|
QStringList features() const
|
|
|
|
{
|
|
|
|
QStringList list;
|
|
|
|
list += "sha1";
|
|
|
|
list += "sha0";
|
|
|
|
list += "ripemd160";
|
|
|
|
list += "md2";
|
|
|
|
list += "md4";
|
|
|
|
list += "md5";
|
2006-02-17 11:32:32 +00:00
|
|
|
#ifdef SHA224_DIGEST_LENGTH
|
|
|
|
list += "sha224";
|
|
|
|
#endif
|
|
|
|
#ifdef SHA256_DIGEST_LENGTH
|
|
|
|
list += "sha256";
|
|
|
|
#endif
|
|
|
|
#ifdef SHA384_DIGEST_LENGTH
|
|
|
|
list += "sha384";
|
|
|
|
#endif
|
|
|
|
#ifdef SHA512_DIGEST_LENGTH
|
|
|
|
list += "sha512";
|
|
|
|
#endif
|
2005-03-14 11:38:23 +00:00
|
|
|
list += "hmac(md5)";
|
|
|
|
list += "hmac(sha1)";
|
|
|
|
list += "hmac(ripemd160)";
|
2005-04-03 09:31:00 +00:00
|
|
|
list += "pbkdf1(md2)";
|
|
|
|
list += "pbkdf1(sha1)";
|
2005-03-21 07:19:14 +00:00
|
|
|
list += "aes128-ecb";
|
|
|
|
list += "aes128-cfb";
|
|
|
|
list += "aes128-cbc";
|
|
|
|
list += "aes128-cbc-pkcs7";
|
2005-03-28 07:58:43 +00:00
|
|
|
list += "aes128-ofb";
|
2005-03-21 07:19:14 +00:00
|
|
|
list += "aes192-ecb";
|
|
|
|
list += "aes192-cfb";
|
|
|
|
list += "aes192-cbc";
|
2005-03-28 07:58:43 +00:00
|
|
|
list += "aes192-ofb";
|
2005-03-21 07:19:14 +00:00
|
|
|
list += "aes256-ecb";
|
|
|
|
list += "aes256-cbc";
|
|
|
|
list += "aes256-cfb";
|
2005-03-28 07:58:43 +00:00
|
|
|
list += "aes256-ofb";
|
2005-03-27 10:39:40 +00:00
|
|
|
list += "blowfish-ecb";
|
2005-04-02 11:50:55 +00:00
|
|
|
list += "blowfish-cbc-pkcs7";
|
|
|
|
list += "blowfish-cbc";
|
|
|
|
list += "blowfish-cfb";
|
|
|
|
list += "blowfish-ofb";
|
2005-03-21 07:19:14 +00:00
|
|
|
list += "tripledes-ecb";
|
|
|
|
list += "des-ecb";
|
2005-03-27 09:37:41 +00:00
|
|
|
list += "des-ecb-pkcs7";
|
|
|
|
list += "des-cbc";
|
|
|
|
list += "des-cbc-pkcs7";
|
|
|
|
list += "des-cfb";
|
|
|
|
list += "des-ofb";
|
2005-03-14 11:38:23 +00:00
|
|
|
list += "pkey";
|
|
|
|
list += "dlgroup";
|
|
|
|
list += "rsa";
|
|
|
|
list += "dsa";
|
|
|
|
list += "dh";
|
|
|
|
list += "cert";
|
|
|
|
list += "csr";
|
|
|
|
list += "crl";
|
2005-06-05 08:49:15 +00:00
|
|
|
list += "pix";
|
2005-04-22 12:46:55 +00:00
|
|
|
list += "tls";
|
2005-05-10 21:10:35 +00:00
|
|
|
list += "cms";
|
2005-03-14 11:38:23 +00:00
|
|
|
|
2004-11-07 10:08:07 +00:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
Context *createContext(const QString &type)
|
|
|
|
{
|
2005-03-14 11:38:23 +00:00
|
|
|
//OpenSSL_add_all_digests();
|
|
|
|
if ( type == "sha1" )
|
2005-03-19 09:09:44 +00:00
|
|
|
return new opensslHashContext( EVP_sha1(), this, type);
|
2005-03-14 11:38:23 +00:00
|
|
|
else if ( type == "sha0" )
|
2005-03-19 09:09:44 +00:00
|
|
|
return new opensslHashContext( EVP_sha(), this, type);
|
2005-03-14 11:38:23 +00:00
|
|
|
else if ( type == "ripemd160" )
|
2005-03-19 09:09:44 +00:00
|
|
|
return new opensslHashContext( EVP_ripemd160(), this, type);
|
2005-03-14 11:38:23 +00:00
|
|
|
else if ( type == "md2" )
|
2005-03-19 09:09:44 +00:00
|
|
|
return new opensslHashContext( EVP_md2(), this, type);
|
2005-03-14 11:38:23 +00:00
|
|
|
else if ( type == "md4" )
|
2005-03-19 09:09:44 +00:00
|
|
|
return new opensslHashContext( EVP_md4(), this, type);
|
2005-03-14 11:38:23 +00:00
|
|
|
else if ( type == "md5" )
|
2005-03-19 09:09:44 +00:00
|
|
|
return new opensslHashContext( EVP_md5(), this, type);
|
2006-02-17 11:32:32 +00:00
|
|
|
#ifdef SHA224_DIGEST_LENGTH
|
|
|
|
else if ( type == "sha224" )
|
|
|
|
return new opensslHashContext( EVP_sha224(), this, type);
|
|
|
|
#endif
|
|
|
|
#ifdef SHA256_DIGEST_LENGTH
|
|
|
|
else if ( type == "sha256" )
|
|
|
|
return new opensslHashContext( EVP_sha256(), this, type);
|
|
|
|
#endif
|
|
|
|
#ifdef SHA384_DIGEST_LENGTH
|
|
|
|
else if ( type == "sha384" )
|
|
|
|
return new opensslHashContext( EVP_sha384(), this, type);
|
|
|
|
#endif
|
|
|
|
#ifdef SHA512_DIGEST_LENGTH
|
|
|
|
else if ( type == "sha512" )
|
|
|
|
return new opensslHashContext( EVP_sha512(), this, type);
|
|
|
|
#endif
|
2005-04-03 09:31:00 +00:00
|
|
|
else if ( type == "pbkdf1(sha1)" )
|
|
|
|
return new opensslPbkdf1Context( EVP_sha1(), this, type );
|
|
|
|
else if ( type == "pbkdf1(md2)" )
|
|
|
|
return new opensslPbkdf1Context( EVP_md2(), this, type );
|
2005-03-14 11:38:23 +00:00
|
|
|
else if ( type == "hmac(md5)" )
|
2005-03-19 07:51:28 +00:00
|
|
|
return new opensslHMACContext( EVP_md5(), this, type );
|
2005-03-14 11:38:23 +00:00
|
|
|
else if ( type == "hmac(sha1)" )
|
2005-03-19 07:51:28 +00:00
|
|
|
return new opensslHMACContext( EVP_sha1(),this, type );
|
2005-03-14 11:38:23 +00:00
|
|
|
else if ( type == "hmac(ripemd160)" )
|
2005-03-19 07:51:28 +00:00
|
|
|
return new opensslHMACContext( EVP_ripemd160(), this, type );
|
2005-03-21 07:19:14 +00:00
|
|
|
else if ( type == "aes128-ecb" )
|
|
|
|
return new opensslCipherContext( EVP_aes_128_ecb(), 0, this, type);
|
|
|
|
else if ( type == "aes128-cfb" )
|
|
|
|
return new opensslCipherContext( EVP_aes_128_cfb(), 0, this, type);
|
|
|
|
else if ( type == "aes128-cbc" )
|
|
|
|
return new opensslCipherContext( EVP_aes_128_cbc(), 0, this, type);
|
|
|
|
else if ( type == "aes128-cbc-pkcs7" )
|
|
|
|
return new opensslCipherContext( EVP_aes_128_cbc(), 1, this, type);
|
2005-03-28 07:58:43 +00:00
|
|
|
else if ( type == "aes128-ofb" )
|
|
|
|
return new opensslCipherContext( EVP_aes_128_ofb(), 0, this, type);
|
2005-03-21 07:19:14 +00:00
|
|
|
else if ( type == "aes192-ecb" )
|
|
|
|
return new opensslCipherContext( EVP_aes_192_ecb(), 0, this, type);
|
|
|
|
else if ( type == "aes192-cfb" )
|
|
|
|
return new opensslCipherContext( EVP_aes_192_cfb(), 0, this, type);
|
|
|
|
else if ( type == "aes192-cbc" )
|
|
|
|
return new opensslCipherContext( EVP_aes_192_cbc(), 0, this, type);
|
2005-03-28 07:58:43 +00:00
|
|
|
else if ( type == "aes192-ofb" )
|
|
|
|
return new opensslCipherContext( EVP_aes_192_ofb(), 0, this, type);
|
2005-03-21 07:19:14 +00:00
|
|
|
else if ( type == "aes256-ecb" )
|
|
|
|
return new opensslCipherContext( EVP_aes_256_ecb(), 0, this, type);
|
|
|
|
else if ( type == "aes256-cfb" )
|
|
|
|
return new opensslCipherContext( EVP_aes_256_cfb(), 0, this, type);
|
|
|
|
else if ( type == "aes256-cbc" )
|
|
|
|
return new opensslCipherContext( EVP_aes_256_cbc(), 0, this, type);
|
2005-03-28 07:58:43 +00:00
|
|
|
else if ( type == "aes256-ofb" )
|
|
|
|
return new opensslCipherContext( EVP_aes_256_ofb(), 0, this, type);
|
2005-03-21 07:19:14 +00:00
|
|
|
else if ( type == "blowfish-ecb" )
|
|
|
|
return new opensslCipherContext( EVP_bf_ecb(), 0, this, type);
|
2005-04-02 11:50:55 +00:00
|
|
|
else if ( type == "blowfish-cfb" )
|
|
|
|
return new opensslCipherContext( EVP_bf_cfb(), 0, this, type);
|
|
|
|
else if ( type == "blowfish-ofb" )
|
|
|
|
return new opensslCipherContext( EVP_bf_ofb(), 0, this, type);
|
|
|
|
else if ( type == "blowfish-cbc" )
|
|
|
|
return new opensslCipherContext( EVP_bf_cbc(), 0, this, type);
|
|
|
|
else if ( type == "blowfish-cbc-pkcs7" )
|
|
|
|
return new opensslCipherContext( EVP_bf_cbc(), 1, this, type);
|
2005-03-21 07:19:14 +00:00
|
|
|
else if ( type == "tripledes-ecb" )
|
|
|
|
return new opensslCipherContext( EVP_des_ede3(), 0, this, type);
|
|
|
|
else if ( type == "des-ecb" )
|
|
|
|
return new opensslCipherContext( EVP_des_ecb(), 0, this, type);
|
2005-03-27 09:37:41 +00:00
|
|
|
else if ( type == "des-ecb-pkcs7" )
|
|
|
|
return new opensslCipherContext( EVP_des_ecb(), 1, this, type);
|
|
|
|
else if ( type == "des-cbc" )
|
|
|
|
return new opensslCipherContext( EVP_des_cbc(), 0, this, type);
|
|
|
|
else if ( type == "des-cbc-pkcs7" )
|
|
|
|
return new opensslCipherContext( EVP_des_cbc(), 1, this, type);
|
|
|
|
else if ( type == "des-cfb" )
|
|
|
|
return new opensslCipherContext( EVP_des_cfb(), 0, this, type);
|
|
|
|
else if ( type == "des-ofb" )
|
|
|
|
return new opensslCipherContext( EVP_des_ofb(), 0, this, type);
|
2005-03-14 11:38:23 +00:00
|
|
|
else if ( type == "pkey" )
|
|
|
|
return new MyPKeyContext( this );
|
|
|
|
else if ( type == "dlgroup" )
|
|
|
|
return new MyDLGroup( this );
|
|
|
|
else if ( type == "rsa" )
|
|
|
|
return new RSAKey( this );
|
|
|
|
else if ( type == "dsa" )
|
|
|
|
return new DSAKey( this );
|
|
|
|
else if ( type == "dh" )
|
|
|
|
return new DHKey( this );
|
|
|
|
else if ( type == "cert" )
|
|
|
|
return new MyCertContext( this );
|
|
|
|
else if ( type == "csr" )
|
|
|
|
return new MyCSRContext( this );
|
|
|
|
else if ( type == "crl" )
|
|
|
|
return new MyCRLContext( this );
|
2005-06-05 08:49:15 +00:00
|
|
|
else if ( type == "pix" )
|
|
|
|
return new MyPIXContext( this );
|
2005-04-22 12:46:55 +00:00
|
|
|
else if ( type == "tls" )
|
|
|
|
return new MyTLSContext( this );
|
2005-05-10 21:10:35 +00:00
|
|
|
else if ( type == "cms" )
|
|
|
|
return new CMSContext( this );
|
2004-12-30 08:20:54 +00:00
|
|
|
return 0;
|
2004-11-07 10:08:07 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2005-02-28 08:20:09 +00:00
|
|
|
class opensslPlugin : public QCAPlugin
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
2006-02-24 08:08:43 +00:00
|
|
|
Q_INTERFACES(QCAPlugin)
|
2005-02-28 08:20:09 +00:00
|
|
|
public:
|
2005-07-07 00:54:12 +00:00
|
|
|
virtual Provider *createProvider() { return new opensslProvider; }
|
2005-02-28 08:20:09 +00:00
|
|
|
};
|
2005-02-28 09:56:07 +00:00
|
|
|
|
|
|
|
#include "qca-openssl.moc"
|
|
|
|
|
2006-02-24 08:08:43 +00:00
|
|
|
Q_EXPORT_PLUGIN2(qca-openssl, opensslPlugin);
|
2005-02-28 09:56:07 +00:00
|
|
|
|