]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
TLS Authority Key Identifier certificate extension
authorChristos Tsantilas <chtsanti@users.sourceforge.net>
Tue, 14 Jun 2016 15:56:12 +0000 (18:56 +0300)
committerChristos Tsantilas <chtsanti@users.sourceforge.net>
Tue, 14 Jun 2016 15:56:12 +0000 (18:56 +0300)
This patch add support for mimicking TLS Authority Key Identifier certificate
extension in Squid generated TLS certificates: If the origin server certificate
has that extension, the generated certificate (via the ssl_crtd daemon or
internally) should have the same extension, with the same set of fields if
possible.

This is a Measurement Factory project

src/ssl/gadgets.cc
src/ssl/gadgets.h

index 218167b3f5a0051581592445dc2e488017b22948..d7dd0813a8a182be92f975c1b9e94d9951bfd9bb 100644 (file)
@@ -264,13 +264,95 @@ std::string & Ssl::CertificateProperties::dbKey() const
     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,
@@ -333,6 +415,9 @@ mimicExtensions(Security::CertPointer & cert, Security::CertPointer const & mimi
         }
     }
 
+    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.
 
@@ -409,7 +494,7 @@ static bool buildCertificate(Security::CertPointer & cert, Ssl::CertificatePrope
             }
         }
 
-        addedExtensions += mimicExtensions(cert, properties.mimicCert);
+        addedExtensions += mimicExtensions(cert, properties.mimicCert, properties.signWithX509);
 
         // According to RFC 5280, using extensions requires v3 certificate.
         if (addedExtensions)
index e6c7324542e2e8a2a95c3acf8fe3af07ce9b74ff..cbd40b3d83d4d58c07e01f3d82219111bc18ad8f 100644 (file)
@@ -15,6 +15,9 @@
 #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
@@ -54,6 +57,9 @@ typedef TidyPointer<BIO, BIO_free_cpp> BIO_Pointer;
 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;
 
@@ -69,6 +75,18 @@ typedef TidyPointer<X509_REQ, X509_REQ_free_cpp> X509_REQ_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.