📄 qca-ossl.cpp
字号:
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)); ++pos; } } break; } default: break; }}static CertificateInfo get_cert_alt_name(X509_EXTENSION *ex){ CertificateInfo info; GENERAL_NAMES *gn = (GENERAL_NAMES *)X509V3_EXT_d2i(ex); 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); GENERAL_NAMES_free(gn); return info;}static X509_EXTENSION *new_cert_key_usage(const Constraints &constraints){ ASN1_BIT_STRING *keyusage = 0; for(int n = 0; n < constraints.count(); ++n) { int bit = -1; switch(constraints[n].known()) { case DigitalSignature: bit = Bit_DigitalSignature; break; case NonRepudiation: bit = Bit_NonRepudiation; break; case KeyEncipherment: bit = Bit_KeyEncipherment; break; case DataEncipherment: bit = Bit_DataEncipherment; break; case KeyAgreement: bit = Bit_KeyAgreement; break; case KeyCertificateSign: bit = Bit_KeyCertificateSign; break; case CRLSign: bit = Bit_CRLSign; break; case EncipherOnly: bit = Bit_EncipherOnly; break; case DecipherOnly: bit = Bit_DecipherOnly; break; default: 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;}static Constraints get_cert_key_usage(X509_EXTENSION *ex){ Constraints constraints; int bit_table[9] = { DigitalSignature, NonRepudiation, KeyEncipherment, DataEncipherment, KeyAgreement, KeyCertificateSign, CRLSign, EncipherOnly, DecipherOnly }; 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)) constraints += ConstraintType((ConstraintTypeKnown)bit_table[n]); } ASN1_BIT_STRING_free(keyusage); return constraints;}static X509_EXTENSION *new_cert_ext_key_usage(const Constraints &constraints){ EXTENDED_KEY_USAGE *extkeyusage = 0; for(int n = 0; n < constraints.count(); ++n) { int nid = -1; // TODO: don't use known/nid, and instead just use OIDs switch(constraints[n].known()) { case ServerAuth: nid = NID_server_auth; break; case ClientAuth: nid = NID_client_auth; break; case CodeSigning: nid = NID_code_sign; break; case EmailProtection: nid = NID_email_protect; break; case IPSecEndSystem: nid = NID_ipsecEndSystem; break; case IPSecTunnel: nid = NID_ipsecTunnel; break; case IPSecUser: nid = NID_ipsecUser; break; case TimeStamping: nid = NID_time_stamp; break; case OCSPSigning: nid = NID_OCSP_sign; break; default: 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;}static Constraints get_cert_ext_key_usage(X509_EXTENSION *ex){ Constraints constraints; 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; // TODO: don't use known/nid, and instead just use OIDs int t = -1; switch(nid) { case NID_server_auth: t = ServerAuth; break; case NID_client_auth: t = ClientAuth; break; case NID_code_sign: t = CodeSigning; break; case NID_email_protect: t = EmailProtection; break; case NID_ipsecEndSystem: t = IPSecEndSystem; break; case NID_ipsecTunnel: t = IPSecTunnel; break; case NID_ipsecUser: t = IPSecUser; break; case NID_time_stamp: t = TimeStamping; break; case NID_OCSP_sign: t = OCSPSigning; break; }; if(t == -1) continue; constraints.append(ConstraintType((ConstraintTypeKnown)t)); } 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;}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;}// If you get any more crashes in this code, please provide a copy// of the cert to bradh AT frogmouth.netstatic QByteArray get_cert_issuer_key_id(X509_EXTENSION *ex){ AUTHORITY_KEYID *akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ex); QByteArray out; if (akid->keyid) out = QByteArray((const char *)ASN1_STRING_data(akid->keyid), ASN1_STRING_length(akid->keyid)); AUTHORITY_KEYID_free(akid); return out;}static Validity convert_verify_error(int err){ // TODO: ErrorExpiredCA Validity rc; switch(err) { case X509_V_ERR_CERT_REJECTED: rc = ErrorRejected; break; case X509_V_ERR_CERT_UNTRUSTED: rc = ErrorUntrusted; 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: rc = ErrorSignatureFailed; 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: rc = ErrorInvalidCA; break; case X509_V_ERR_INVALID_PURPOSE: // note: not used by store verify rc = ErrorInvalidPurpose; break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: rc = ErrorSelfSigned; break; case X509_V_ERR_CERT_REVOKED: rc = ErrorRevoked; break; case X509_V_ERR_PATH_LENGTH_EXCEEDED: rc = ErrorPathLengthExceeded; 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: rc = ErrorExpired; 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: rc = ErrorValidityUnknown; break; } return rc;}EVP_PKEY *qca_d2i_PKCS8PrivateKey(const SecureArray &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;}class opensslHashContext : public HashContext{public: opensslHashContext(const EVP_MD *algorithm, Provider *p, const QString &type) : HashContext(p, type) { m_algorithm = algorithm; EVP_DigestInit( &m_context, m_algorithm ); } ~opensslHashContext() { EVP_MD_CTX_cleanup(&m_context); } void clear() { EVP_MD_CTX_cleanup(&m_context); EVP_DigestInit( &m_context, m_algorithm ); } void update(const MemoryRegion &a) { EVP_DigestUpdate( &m_context, (unsigned char*)a.data(), a.size() ); } MemoryRegion final() { SecureArray a( EVP_MD_size( m_algorithm ) ); EVP_DigestFinal( &m_context, (unsigned char*)a.data(), 0 ); return a; } Provider::Context *clone() const { return new opensslHashContext(*this); }protected: const EVP_MD *m_algorithm; EVP_MD_CTX m_context;};class opensslPbkdf1Context : public KDFContext{public: opensslPbkdf1Context(const EVP_MD *algorithm, Provider *p, const QString &type) : KDFContext(p, type) { m_algorithm = algorithm; EVP_DigestInit( &m_context, m_algorithm ); } Provider::Context *clone() const { return new opensslPbkdf1Context( *this ); } SymmetricKey makeKey(const SecureArray &secret, const InitializationVector &salt, 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; return SymmetricKey(); } /* 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() ); SecureArray 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;};class opensslPbkdf2Context : public KDFContext{public: opensslPbkdf2Context(Provider *p, const QString &type) : KDFContext(p, type) { } Provider::Context *clone() const { return new opensslPbkdf2Context( *this ); } SymmetricKey makeKey(const SecureArray &secret, const InitializationVector &salt, unsigned int keyLength, unsigned int iterationCount) { SecureArray out(keyLength); PKCS5_PBKDF2_HMAC_SHA1( (char*)secret.data(), secret.size(), (unsigned char*)salt.data(), salt.size(), iterationCount, keyLength, (unsigned char*)out.data() ); return out; }protected:};class opensslHMACContext : public MACContext{public: opensslHMACContext(const EVP_MD *algorithm, Provider *p, const QString &type) : MACContext(p, type) { m_algorithm = algorithm; HMAC_CTX_init( &m_context ); } void setup(const SymmetricKey &key) { HMAC_Init_ex( &m_context, key.data(), key.size(), m_algorithm, 0 ); } KeyLength keyLength() const { return anyKeyLength(); } void update(const MemoryRegion &a) { HMAC_Update( &m_context, (unsigned char *)a.data(), a.size() ); } void final(MemoryRegion *out) { SecureArray sa( EVP_MD_size( m_algorithm ), 0 ); HMAC_Final(&m_context, (unsigned char *)sa.data(), 0 ); HMAC_CTX_cleanup(&m_context); *out = sa; } Provider::Context *clone() const { return new opensslHMACContext(*this); }protected: HMAC_CTX m_context; const EVP_MD *m_algorithm;};//----------------------------------------------------------------------------// EVPKey//----------------------------------------------------------------------------// note: this class squelches processing errors, since QCA doesn't care about themclass EVPKey{public: enum State { Idle, SignActive, SignError, VerifyActive, VerifyError }; EVP_PKEY *pkey; EVP_MD_CTX mdctx; State state; bool raw_type; SecureArray raw;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -