]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Check the commonName of the signer of the root.xml file in
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 3 Jan 2013 14:38:38 +0000 (14:38 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 3 Jan 2013 14:38:38 +0000 (14:38 +0000)
  unbound-anchor, default is dnssec@iana.org.

git-svn-id: file:///svn/unbound/trunk@2804 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
doc/unbound-anchor.8.in
smallapp/unbound-anchor.c

index c4fb0caef8c749c912d2286169586fc438226645..36ae697b273961aa639639c4acbfe4785f55908a 100644 (file)
@@ -2,6 +2,8 @@
        - Test that unbound-control checks client credentials.
        - Test that unbound can handle a CNAME at an intermediate node in
          the chain of trust (where it seeks a DS record).
+       - Check the commonName of the signer of the root.xml file in
+         unbound-anchor, default is dnssec@iana.org.
 
 2 January 2013: Wouter
        - Fix openssl lock free on exit (reported by Robert Fleischman).
index 00d881ea4c276aaf842eb91f319dee62728bf77f..0848fac029a9a62ca42185d5d03a79335b31f0a2 100644 (file)
@@ -77,6 +77,11 @@ The pathname to the root\-anchors.p7s file on the server. (forms URL with \-u).
 The default is /root\-anchors/root\-anchors.p7s.  This file has to be a PKCS7
 signature over the xml file, using the pem file (\-c) as trust anchor.
 .TP
+.B \-n \fIname
+The commonName for the Subject of the signer's certificate from the p7s
+signature file.  Only signatures from this name are allowed.  default is
+dnssec@iana.org.  If you pass "" then the commonName is not checked.
+.TP
 .B \-4
 Use IPv4 for domain resolution and contacting the server on https.  Default is
 to use IPv4 and IPv6 where appropriate.
index 1448002baaef3068b30082c83c1eb5a978340996..d02eb6474b17199bb765a3ae781977894755fe4c 100644 (file)
 #define XMLNAME "root-anchors/root-anchors.xml"
 /** path on HTTPS server to p7s file */
 #define P7SNAME "root-anchors/root-anchors.p7s"
+/** name of the signer of the certificate */
+#define P7SIGNER "dnssec@iana.org"
 /** port number for https access */
 #define HTTPS_PORT 443
 
@@ -184,6 +186,7 @@ usage()
        printf("-u name         server in https url, default %s\n", URLNAME);
        printf("-x path         pathname to xml in url, default %s\n", XMLNAME);
        printf("-s path         pathname to p7s in url, default %s\n", P7SNAME);
+       printf("-n name         signer's subject commonName, default %s\n", P7SIGNER);
        printf("-4              work using IPv4 only\n");
        printf("-6              work using IPv6 only\n");
        printf("-f resolv.conf  use given resolv.conf to resolve -u name\n");
@@ -1623,12 +1626,76 @@ xml_parse(BIO* xml, time_t now)
        }
 }
 
+/** get valid signers from the list of signers in the signature */
+static STACK_OF(X509)*
+get_valid_signers(PKCS7* p7, char* p7signer)
+{
+       int i;
+       STACK_OF(X509)* validsigners = sk_X509_new_null();
+       STACK_OF(X509)* signers = PKCS7_get0_signers(p7, NULL, 0);
+       if(!validsigners) {
+               if(verb) printf("out of memory\n");
+               sk_X509_free(signers);
+               return NULL;
+       }
+       if(!signers) {
+               if(verb) printf("no signers in pkcs7 signature\n");
+               sk_X509_free(validsigners);
+               return NULL;
+       }
+       if(!p7signer || strcmp(p7signer, "")==0) {
+               /* there is no name to check, return all records */
+               if(verb) printf("did not check commonName of signer\n");
+               sk_X509_free(validsigners);
+               return signers;
+       }
+       for(i=0; i<sk_X509_num(signers); i++) {
+               X509_NAME* nm = X509_get_subject_name(
+                       sk_X509_value(signers, i));
+               char buf[1024];
+               if(!nm) {
+                       if(verb) printf("signers cert has no subject name\n");
+                       sk_X509_free(signers);
+                       sk_X509_free(validsigners);
+                       return 0;
+               }
+               if(verb) {
+                       char* nmline = X509_NAME_oneline(nm, buf,
+                               (int)sizeof(buf));
+                       printf("signer %d: Subject: %s\n", i,
+                               nmline?nmline:"no subject");
+                       if(verb >= 3 && X509_NAME_get_text_by_NID(nm,
+                               NID_commonName, buf, (int)sizeof(buf)))
+                               printf("commonName: %s\n", buf);
+                       if(verb >= 3 && X509_NAME_get_text_by_NID(nm,
+                               NID_pkcs9_emailAddress, buf, (int)sizeof(buf)))
+                               printf("emailAddress: %s\n", buf);
+               }
+               if(!X509_NAME_get_text_by_NID(nm, NID_commonName,
+                       buf, (int)sizeof(buf))) {
+                       if(verb) printf("removed cert with no name\n");
+                       continue; /* no name, no use */
+               }
+               if(strcmp(buf, p7signer) != 0) {
+                       if(verb) printf("removed cert with wrong name\n");
+                       continue; /* wrong name, skip it */
+               }
+
+               /* we like this cert, add it to our list of valid
+                * signers certificates */
+               sk_X509_push(validsigners, sk_X509_value(signers, i));
+       }
+       sk_X509_free(signers);
+       return validsigners;
+}
+
 /** verify a PKCS7 signature, false on failure */
 static int
-verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust)
+verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust, char* p7signer)
 {
        PKCS7* p7;
        X509_STORE *store = X509_STORE_new();
+       STACK_OF(X509)* validsigners;
        int secure = 0;
        int i;
 #ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
@@ -1650,6 +1717,9 @@ verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust)
 #endif
                return 0;
        }
+#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
+       X509_VERIFY_PARAM_free(param);
+#endif
 
        (void)BIO_reset(p7s);
        (void)BIO_reset(data);
@@ -1674,7 +1744,15 @@ verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust)
        }
        if(verb >= 2) printf("setup the X509_STORE\n");
 
-       if(PKCS7_verify(p7, NULL, store, data, NULL, 0) == 1) {
+       /* check what is in the Subject name of the certificates,
+        * and build a stack that contains only the right certificates */
+       validsigners = get_valid_signers(p7, p7signer);
+       if(!validsigners) {
+                       X509_STORE_free(store);
+                       PKCS7_free(p7);
+                       return 0;
+       }
+       if(PKCS7_verify(p7, validsigners, store, data, NULL, PKCS7_NOINTERN) == 1) {
                secure = 1;
                if(verb) printf("the PKCS7 signature verified\n");
        } else {
@@ -1683,6 +1761,7 @@ verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust)
                }
        }
 
+       sk_X509_free(validsigners);
        X509_STORE_free(store);
        PKCS7_free(p7);
        return secure;
@@ -1743,12 +1822,12 @@ write_root_anchor(char* root_anchor_file, BIO* ds)
 /** Perform the verification and update of the trustanchor file */
 static void
 verify_and_update_anchor(char* root_anchor_file, BIO* xml, BIO* p7s,
-       STACK_OF(X509)* cert)
+       STACK_OF(X509)* cert, char* p7signer)
 {
        BIO* ds;
 
        /* verify xml file */
-       if(!verify_p7sig(xml, p7s, cert)) {
+       if(!verify_p7sig(xml, p7s, cert, p7signer)) {
                printf("the PKCS7 signature failed\n");
                exit(0);
        }
@@ -1772,7 +1851,7 @@ static void do_wsa_cleanup(void) { WSACleanup(); }
 /** perform actual certupdate work */
 static int
 do_certupdate(char* root_anchor_file, char* root_cert_file,
-       char* urlname, char* xmlname, char* p7sname,
+       char* urlname, char* xmlname, char* p7sname, char* p7signer,
        char* res_conf, char* root_hints, char* debugconf,
        int ip4only, int ip6only, int port, struct ub_result* dnskey)
 {
@@ -1805,7 +1884,7 @@ do_certupdate(char* root_anchor_file, char* root_cert_file,
        p7s = https(ip_list, p7sname, urlname);
 
        /* verify and update the root anchor */
-       verify_and_update_anchor(root_anchor_file, xml, p7s, cert);
+       verify_and_update_anchor(root_anchor_file, xml, p7s, cert, p7signer);
        if(verb) printf("success: the anchor has been updated "
                        "using the cert\n");
 
@@ -2055,7 +2134,7 @@ probe_date_allows_certupdate(char* root_anchor_file)
 /** perform the unbound-anchor work */
 static int
 do_root_update_work(char* root_anchor_file, char* root_cert_file,
-       char* urlname, char* xmlname, char* p7sname,
+       char* urlname, char* xmlname, char* p7sname, char* p7signer,
        char* res_conf, char* root_hints, char* debugconf,
        int ip4only, int ip6only, int force, int port)
 {
@@ -2088,8 +2167,8 @@ do_root_update_work(char* root_anchor_file, char* root_cert_file,
        if((dnskey->rcode == 0 &&
                probe_date_allows_certupdate(root_anchor_file)) || force) {
                if(do_certupdate(root_anchor_file, root_cert_file, urlname,
-                       xmlname, p7sname, res_conf, root_hints, debugconf,
-                       ip4only, ip6only, port, dnskey))
+                       xmlname, p7sname, p7signer, res_conf, root_hints,
+                       debugconf, ip4only, ip6only, port, dnskey))
                        return 1;
                return used_builtin;
        }
@@ -2112,12 +2191,13 @@ int main(int argc, char* argv[])
        char* urlname = URLNAME;
        char* xmlname = XMLNAME;
        char* p7sname = P7SNAME;
+       char* p7signer = P7SIGNER;
        char* res_conf = NULL;
        char* root_hints = NULL;
        char* debugconf = NULL;
        int dolist=0, ip4only=0, ip6only=0, force=0, port = HTTPS_PORT;
        /* parse the options */
-       while( (c=getopt(argc, argv, "46C:FP:a:c:f:hlr:s:u:vx:")) != -1) {
+       while( (c=getopt(argc, argv, "46C:FP:a:c:f:hln:r:s:u:vx:")) != -1) {
                switch(c) {
                case 'l':
                        dolist = 1;
@@ -2143,6 +2223,9 @@ int main(int argc, char* argv[])
                case 's':
                        p7sname = optarg;
                        break;
+               case 'n':
+                       p7signer = optarg;
+                       break;
                case 'f':
                        res_conf = optarg;
                        break;
@@ -2180,6 +2263,6 @@ int main(int argc, char* argv[])
        if(dolist) do_list_builtin();
 
        return do_root_update_work(root_anchor_file, root_cert_file, urlname,
-               xmlname, p7sname, res_conf, root_hints, debugconf, ip4only,
-               ip6only, force, port);
+               xmlname, p7sname, p7signer, res_conf, root_hints, debugconf,
+               ip4only, ip6only, force, port);
 }