From 69a70afa8b22ee4ee72ccf583db2efd249e36721 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Tue, 5 Jan 2016 14:54:02 +0000 Subject: [PATCH] DKIM: fix base64 decode to ignore whitespace; needed for private-key input from file. Use this for general-purpose b64decode also. Testsuite: DKIM signing testcase --- src/src/base64.c | 17 +++++-- src/src/pdkim/pdkim-rsa.c | 20 +++++++- src/src/pdkim/pdkim.c | 8 +++- test/confs/4503 | 47 +++++++++++++++++++ test/dnszones-src/db.test.ex | 2 +- test/log/4503 | 9 ++++ .../4500-Domain-Keys-Identified-Mail/4503 | 10 ++++ 7 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 test/confs/4503 create mode 100644 test/log/4503 create mode 100644 test/scripts/4500-Domain-Keys-Identified-Mail/4503 diff --git a/src/src/base64.c b/src/src/base64.c index f4c4f233b..61b600f6c 100644 --- a/src/src/base64.c +++ b/src/src/base64.c @@ -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; } diff --git a/src/src/pdkim/pdkim-rsa.c b/src/src/pdkim/pdkim-rsa.c index 87cbac130..7f98fb008 100644 --- a/src/src/pdkim/pdkim-rsa.c +++ b/src/src/pdkim/pdkim-rsa.c @@ -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 ); } diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c index bd05c51b5..f93bda087 100644 --- a/src/src/pdkim/pdkim.c +++ b/src/src/pdkim/pdkim.c @@ -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 index 000000000..e9f2d5d47 --- /dev/null +++ b/test/confs/4503 @@ -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 diff --git a/test/dnszones-src/db.test.ex b/test/dnszones-src/db.test.ex index 859626106..cde5b4321 100644 --- a/test/dnszones-src/db.test.ex +++ b/test/dnszones-src/db.test.ex @@ -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 index 000000000..056b52946 --- /dev/null +++ b/test/log/4503 @@ -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: 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 index 000000000..7ca338275 --- /dev/null +++ b/test/scripts/4500-Domain-Keys-Identified-Mail/4503 @@ -0,0 +1,10 @@ +# DKIM signing +# +exim -bd -DSERVER=server -oX PORT_D +**** +exim a@test.ex +content +**** +millisleep 200 +killdaemon +no_msglog_check -- 2.30.2