DKIM: fix base64 decode to ignore whitespace; needed for private-key input
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 5 Jan 2016 14:54:02 +0000 (14:54 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 5 Jan 2016 16:46:36 +0000 (16:46 +0000)
from file.  Use this for general-purpose b64decode also.
Testsuite: DKIM signing testcase

src/src/base64.c
src/src/pdkim/pdkim-rsa.c
src/src/pdkim/pdkim.c
test/confs/4503 [new file with mode: 0644]
test/dnszones-src/db.test.ex
test/log/4503 [new file with mode: 0644]
test/scripts/4500-Domain-Keys-Identified-Mail/4503 [new file with mode: 0644]

index f4c4f23..61b600f 100644 (file)
@@ -134,6 +134,7 @@ Arguments:
 Returns:      the number of bytes in the result,
               or -1 if the input was malformed
 
+Whitespace in the input is ignored.
 A zero is added on to the end to make it easy in cases where the result is to
 be interpreted as text. This is not included in the count. */
 
@@ -161,21 +162,29 @@ quantum this may decode to 1, 2, or 3 output bytes. */
 
 while ((x = *code++) != 0)
   {
+  if (isspace(x)) continue;
+
   if (x > 127 || (x = dec64table[x]) == 255) return -1;
-  if ((y = *code++) == 0 || (y = dec64table[y]) == 255)
+
+  while (isspace(y = *code++)) ;
+  if (y == 0 || (y = dec64table[y]) == 255)
     return -1;
 
   *result++ = (x << 2) | (y >> 4);
 
-  if ((x = *code++) == '=')
+  while (isspace(x = *code++)) ;
+  if (x == '=')
     {
-    if (*code++ != '=' || *code != 0) return -1;
+    while (isspace(x = *code++)) ;
+    if (x != '=' || *code != 0) return -1;
     }
   else
     {
     if (x > 127 || (x = dec64table[x]) == 255) return -1;
     *result++ = (y << 4) | (x >> 2);
-    if ((y = (*code++)) == '=')
+
+    while (isspace(y = *code++)) ;
+    if (y == '=')
       {
       if (*code != 0) return -1;
       }
index 87cbac1..7f98fb0 100644 (file)
@@ -82,17 +82,25 @@ int rsa_parse_key( rsa_context *rsa, unsigned char *buf, int buflen,
             "-----END RSA PRIVATE KEY-----" );
 
         if( s2 == NULL || s2 <= s1 )
+{
+debug_printf("rsa_parse_key: err 1\n");
             return( POLARSSL_ERR_X509_KEY_INVALID_PEM );
+}
 
         s1 += 31;
         if( *s1 == '\r' ) s1++;
         if( *s1 == '\n' ) s1++;
-            else return( POLARSSL_ERR_X509_KEY_INVALID_PEM );
+            else
+{
+debug_printf("rsa_parse_key: err 2\n");
+ return( POLARSSL_ERR_X509_KEY_INVALID_PEM );
+}
 
         enc = 0;
 
         if( memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 )
         {
+debug_printf("rsa_parse_key: err 3\n");
             return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
         }
 
@@ -104,14 +112,18 @@ int rsa_parse_key( rsa_context *rsa, unsigned char *buf, int buflen,
 
        s1 = string_copyn(s1, s2-s1); /* need nul-terminated string */
        if ((len = b64decode(s1, &buf)) < 0)
+{
+debug_printf("rsa_parse_key: err 4\n");
             return POLARSSL_ERR_BASE64_INVALID_CHARACTER
                | POLARSSL_ERR_X509_KEY_INVALID_PEM;
+}
        }
 
         buflen = len;
 
         if( enc != 0 )
         {
+debug_printf("rsa_parse_key: err 5\n");
             return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
         }
     }
@@ -139,6 +151,7 @@ int rsa_parse_key( rsa_context *rsa, unsigned char *buf, int buflen,
             ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
     {
         rsa_free( rsa );
+debug_printf("rsa_parse_key: err 6\n");
         return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT | ret );
     }
 
@@ -147,12 +160,14 @@ int rsa_parse_key( rsa_context *rsa, unsigned char *buf, int buflen,
     if( ( ret = asn1_get_int( &p, end, &rsa->ver ) ) != 0 )
     {
         rsa_free( rsa );
+debug_printf("rsa_parse_key: err 7\n");
         return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT | ret );
     }
 
     if( rsa->ver != 0 )
     {
         rsa_free( rsa );
+debug_printf("rsa_parse_key: err 8\n");
         return( ret | POLARSSL_ERR_X509_KEY_INVALID_VERSION );
     }
 
@@ -166,6 +181,7 @@ int rsa_parse_key( rsa_context *rsa, unsigned char *buf, int buflen,
         ( ret = asn1_get_mpi( &p, end, &rsa->QP ) ) != 0 )
     {
         rsa_free( rsa );
+debug_printf("rsa_parse_key: err 9\n");
         return( ret | POLARSSL_ERR_X509_KEY_INVALID_FORMAT );
     }
 
@@ -174,6 +190,7 @@ int rsa_parse_key( rsa_context *rsa, unsigned char *buf, int buflen,
     if( p != end )
     {
         rsa_free( rsa );
+debug_printf("rsa_parse_key: err 10\n");
         return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT |
                 POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
     }
@@ -181,6 +198,7 @@ int rsa_parse_key( rsa_context *rsa, unsigned char *buf, int buflen,
     if( ( ret = rsa_check_privkey( rsa ) ) != 0 )
     {
         rsa_free( rsa );
+debug_printf("rsa_parse_key: err 11\n");
         return( ret );
     }
 
index bd05c51..f93bda0 100644 (file)
@@ -1759,13 +1759,17 @@ while (sig)
   if (ctx->mode == PDKIM_MODE_SIGN)
     {
     rsa_context rsa;
+int perr;
 
     rsa_init(&rsa, RSA_PKCS_V15, 0);
 
     /* Perform private key operation */
-    if (rsa_parse_key(&rsa, (unsigned char *)sig->rsa_privkey,
-                     strlen(sig->rsa_privkey), NULL, 0) != 0)
+    if ((perr = rsa_parse_key(&rsa, (unsigned char *)sig->rsa_privkey,
+                     strlen(sig->rsa_privkey), NULL, 0)) != 0)
+{
+debug_printf("rsa_parse_key: perr 0x%x\n", perr);
       return PDKIM_ERR_RSA_PRIVKEY;
+}
 
     sig->sigdata_len = mpi_size(&(rsa.N));
     sig->sigdata = store_get(sig->sigdata_len);
diff --git a/test/confs/4503 b/test/confs/4503
new file mode 100644 (file)
index 0000000..e9f2d5d
--- /dev/null
@@ -0,0 +1,47 @@
+# Exim test configuration 4503
+
+SERVER=
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+primary_hostname = myhost.test.ex
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/SERVER%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+tls_advertise_hosts =
+
+# ----- Main settings -----
+
+log_selector = +outgoing_port
+acl_smtp_rcpt = accept
+acl_smtp_dkim = accept logwrite = signer: $dkim_cur_signer bits: $dkim_key_length
+
+# ----- Routers
+
+begin routers
+
+server_dump:
+  driver = redirect
+  condition = ${if eq {SERVER}{server}{yes}{no}}
+  data = :blackhole:
+
+client:
+  driver = accept
+  transport = send_to_server
+
+# ----- Transports
+
+begin transports
+
+send_to_server:
+  driver = smtp
+  allow_localhost
+  hosts = HOSTIPV4
+  port = PORT_D
+
+  dkim_domain =                test.ex
+  dkim_selector =      sel
+  dkim_private_key =   DIR/aux-fixed/dkim/dkim.private
+
+# End
index 8596261..cde5b43 100644 (file)
@@ -472,7 +472,7 @@ DELAY=1500 delay1500 A HOSTIPV4
 
 ; ------- DKIM ---------
 
-; public key, base64 - matches private key in aux-fixed/dkim/dkim/private
+; public key, base64 - matches private key in aux-fixed/dkim/dkim.private
 ;  openssl genrsa -out aux-fixed/dkim/dkim.private 1024
 ;  openssl rsa -in aux-fixed/dkim/dkim.private -out /dev/stdout -pubout -outform PEM
 ;
diff --git a/test/log/4503 b/test/log/4503
new file mode 100644 (file)
index 0000000..056b529
--- /dev/null
@@ -0,0 +1,9 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmaY-0005vi-00 signer: test.ex bits: 1024
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <a@test.ex> R=server_dump
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
diff --git a/test/scripts/4500-Domain-Keys-Identified-Mail/4503 b/test/scripts/4500-Domain-Keys-Identified-Mail/4503
new file mode 100644 (file)
index 0000000..7ca3382
--- /dev/null
@@ -0,0 +1,10 @@
+# DKIM signing
+#
+exim -bd -DSERVER=server -oX PORT_D
+****
+exim a@test.ex
+content
+****
+millisleep 200
+killdaemon
+no_msglog_check