return certKey;
}
+/// Check if mimicCert certificate has the Authority Key Identifier extension
+/// and if yes add the extension to cert certificate with the same fields if
+/// possible. If the issuerCert certificate does not have the Subject Key
+/// Identifier extension (required to build the keyIdentifier field of
+/// AuthorityKeyIdentifier) then the authorityCertIssuer and
+/// authorityCertSerialNumber fields added.
+static bool
+mimicAuthorityKeyId(Security::CertPointer &cert, Security::CertPointer const &mimicCert, Security::CertPointer const &issuerCert)
+{
+ if (!mimicCert.get() || !issuerCert.get())
+ return false;
+
+ Ssl::AUTHORITY_KEYID_Pointer akid((AUTHORITY_KEYID *)X509_get_ext_d2i(mimicCert.get(), NID_authority_key_identifier, nullptr, nullptr));
+
+ bool addKeyId = false, addIssuer = false;
+ if (akid.get()) {
+ addKeyId = (akid.get()->keyid != nullptr);
+ addIssuer = (akid.get()->issuer && akid.get()->serial);
+ }
+
+ if (!addKeyId && !addIssuer)
+ return false; // No need to add AuthorityKeyIdentifier
+
+ Ssl::ASN1_OCTET_STRING_Pointer issuerKeyId;
+ if (addKeyId) {
+ X509_EXTENSION *ext;
+ // Check if the issuer has the Subject Key Identifier extension
+ const int indx = X509_get_ext_by_NID(issuerCert.get(), NID_subject_key_identifier, -1);
+ if (indx >= 0 && (ext = X509_get_ext(issuerCert.get(), indx))) {
+ issuerKeyId.reset((ASN1_OCTET_STRING *)X509V3_EXT_d2i(ext));
+ }
+ }
+
+ Ssl::X509_NAME_Pointer issuerName;
+ Ssl::ASN1_INT_Pointer issuerSerial;
+ if (issuerKeyId.get() == nullptr || addIssuer) {
+ issuerName.reset(X509_NAME_dup(X509_get_issuer_name(issuerCert.get())));
+ issuerSerial.reset(M_ASN1_INTEGER_dup(X509_get_serialNumber(issuerCert.get())));
+ }
+
+ Ssl::AUTHORITY_KEYID_Pointer theAuthKeyId(AUTHORITY_KEYID_new());
+ if (!theAuthKeyId.get())
+ return false;
+ theAuthKeyId.get()->keyid = issuerKeyId.release();
+ if (issuerName && issuerSerial) {
+ Ssl::GENERAL_NAME_STACK_Pointer genNames(sk_GENERAL_NAME_new_null());
+ if (genNames.get()) {
+ if (GENERAL_NAME *aname = GENERAL_NAME_new()) {
+ sk_GENERAL_NAME_push(genNames.get(), aname);
+ aname->type = GEN_DIRNAME;
+ aname->d.dirn = issuerName.release();
+ theAuthKeyId.get()->issuer = genNames.release();
+ theAuthKeyId.get()->serial = issuerSerial.release();
+ }
+ }
+ }
+
+ // The Authority Key Identifier extension should include KeyId or/and both
+ /// issuer name and issuer serial
+ if (!theAuthKeyId.get()->keyid && (!theAuthKeyId.get()->issuer || !theAuthKeyId.get()->serial))
+ return false;
+
+ const X509V3_EXT_METHOD *method = X509V3_EXT_get_nid(NID_authority_key_identifier);
+ if (!method)
+ return false;
+
+ unsigned char *ext_der = NULL;
+ int ext_len = ASN1_item_i2d((ASN1_VALUE *)theAuthKeyId.get(), &ext_der, ASN1_ITEM_ptr(method->it));
+ Ssl::ASN1_OCTET_STRING_Pointer extOct(M_ASN1_OCTET_STRING_new());
+ extOct.get()->data = ext_der;
+ extOct.get()->length = ext_len;
+ Ssl::X509_EXTENSION_Pointer extAuthKeyId(X509_EXTENSION_create_by_NID(NULL, NID_authority_key_identifier, 0, extOct.get()));
+ if (!extAuthKeyId.get())
+ return false;
+
+ extOct.release();
+ if (!X509_add_ext(cert.get(), extAuthKeyId.get(), -1))
+ return false;
+
+ return true;
+}
+
/// Copy certificate extensions from cert to mimicCert.
/// Returns the number of extensions copied.
// Currently only extensions which are reported by the users that required are
// mimicked. More safe to mimic extensions would be added here if users request
// them.
static int
-mimicExtensions(Security::CertPointer & cert, Security::CertPointer const & mimicCert)
+mimicExtensions(Security::CertPointer & cert, Security::CertPointer const &mimicCert, Security::CertPointer const &issuerCert)
{
static int extensions[]= {
NID_key_usage,
}
}
+ if (mimicAuthorityKeyId(cert, mimicCert, issuerCert))
+ ++added;
+
// We could also restrict mimicking of the CA extension to CA:FALSE
// because Squid does not generate valid fake CA certificates.
}
}
- addedExtensions += mimicExtensions(cert, properties.mimicCert);
+ addedExtensions += mimicExtensions(cert, properties.mimicCert, properties.signWithX509);
// According to RFC 5280, using extensions requires v3 certificate.
if (addedExtensions)
#if HAVE_OPENSSL_TXT_DB_H
#include <openssl/txt_db.h>
#endif
+#if HAVE_OPENSSL_X509V3_H
+#include <openssl/x509v3.h>
+#endif
#include <string>
namespace Ssl
CtoCpp1(ASN1_INTEGER_free, ASN1_INTEGER *)
typedef TidyPointer<ASN1_INTEGER, ASN1_INTEGER_free_cpp> ASN1_INT_Pointer;
+CtoCpp1(ASN1_OCTET_STRING_free, ASN1_OCTET_STRING *)
+typedef TidyPointer<ASN1_OCTET_STRING, ASN1_OCTET_STRING_free_cpp> ASN1_OCTET_STRING_Pointer;
+
CtoCpp1(TXT_DB_free, TXT_DB *)
typedef TidyPointer<TXT_DB, TXT_DB_free_cpp> TXT_DB_Pointer;
sk_free_wrapper(sk_X509_NAME, STACK_OF(X509_NAME) *, X509_NAME_free)
typedef TidyPointer<STACK_OF(X509_NAME), sk_X509_NAME_free_wrapper> X509_NAME_STACK_Pointer;
+CtoCpp1(AUTHORITY_KEYID_free, AUTHORITY_KEYID *)
+typedef TidyPointer<AUTHORITY_KEYID, AUTHORITY_KEYID_free_cpp> AUTHORITY_KEYID_Pointer;
+
+sk_free_wrapper(sk_GENERAL_NAME, STACK_OF(GENERAL_NAME) *, GENERAL_NAME_free)
+typedef TidyPointer<STACK_OF(GENERAL_NAME), sk_GENERAL_NAME_free_wrapper> GENERAL_NAME_STACK_Pointer;
+
+CtoCpp1(GENERAL_NAME_free, GENERAL_NAME *)
+typedef TidyPointer<GENERAL_NAME, GENERAL_NAME_free_cpp> GENERAL_NAME_Pointer;
+
+CtoCpp1(X509_EXTENSION_free, X509_EXTENSION *)
+typedef TidyPointer<X509_EXTENSION, X509_EXTENSION_free_cpp> X509_EXTENSION_Pointer;
+
/**
\ingroup SslCrtdSslAPI
* Create 1024 bits rsa key.