From f16784449dd011fc8e79b353854891c98ccc61b4 Mon Sep 17 00:00:00 2001 From: ketmar Date: Sat, 10 Aug 2013 04:26:20 +0300 Subject: [PATCH] initial commit; it works --- Jamfile | 4 + Jamrules | 14 + crtgen/certgen.sh | 3 + crtgen/creds.txt | 9 + src/Jamfile | 14 + src/fuckme.c | 292 +++ src/libk8clock/Jamfile | 6 + src/libk8clock/k8clock.c | 113 ++ src/libk8clock/k8clock.h | 47 + src/libpolarssl/Jamfile | 50 + src/libpolarssl/aes.c | 1352 ++++++++++++++ src/libpolarssl/aes.h | 202 ++ src/libpolarssl/arc4.c | 173 ++ src/libpolarssl/arc4.h | 98 + src/libpolarssl/asn1.h | 246 +++ src/libpolarssl/asn1parse.c | 260 +++ src/libpolarssl/asn1write.c | 241 +++ src/libpolarssl/asn1write.h | 46 + src/libpolarssl/base64.c | 262 +++ src/libpolarssl/base64.h | 87 + src/libpolarssl/bignum.c | 2143 +++++++++++++++++++++ src/libpolarssl/bignum.h | 685 +++++++ src/libpolarssl/blowfish.c | 632 +++++++ src/libpolarssl/blowfish.h | 171 ++ src/libpolarssl/bn_mul.h | 864 +++++++++ src/libpolarssl/camellia.c | 1035 +++++++++++ src/libpolarssl/camellia.h | 200 ++ src/libpolarssl/certs.c | 196 ++ src/libpolarssl/certs.h | 47 + src/libpolarssl/cipher.c | 601 ++++++ src/libpolarssl/cipher.h | 463 +++++ src/libpolarssl/cipher_wrap.c | 711 +++++++ src/libpolarssl/cipher_wrap.h | 107 ++ src/libpolarssl/config.h | 1012 ++++++++++ src/libpolarssl/ctr_drbg.c | 562 ++++++ src/libpolarssl/ctr_drbg.h | 231 +++ src/libpolarssl/debug.c | 238 +++ src/libpolarssl/debug.h | 89 + src/libpolarssl/des.c | 997 ++++++++++ src/libpolarssl/des.h | 252 +++ src/libpolarssl/dhm.c | 302 +++ src/libpolarssl/dhm.h | 244 +++ src/libpolarssl/entropy.c | 204 ++ src/libpolarssl/entropy.h | 153 ++ src/libpolarssl/entropy_poll.c | 136 ++ src/libpolarssl/entropy_poll.h | 75 + src/libpolarssl/error.c | 612 ++++++ src/libpolarssl/error.h | 108 ++ src/libpolarssl/gcm.c | 621 +++++++ src/libpolarssl/gcm.h | 147 ++ src/libpolarssl/havege.c | 231 +++ src/libpolarssl/havege.h | 71 + src/libpolarssl/md.c | 297 +++ src/libpolarssl/md.h | 363 ++++ src/libpolarssl/md2.c | 368 ++++ src/libpolarssl/md2.h | 171 ++ src/libpolarssl/md4.c | 464 +++++ src/libpolarssl/md4.h | 177 ++ src/libpolarssl/md5.c | 585 ++++++ src/libpolarssl/md5.h | 182 ++ src/libpolarssl/md_wrap.c | 733 ++++++++ src/libpolarssl/md_wrap.h | 64 + src/libpolarssl/net.c | 374 ++++ src/libpolarssl/net.h | 161 ++ src/libpolarssl/openssl.h | 136 ++ src/libpolarssl/padlock.c | 162 ++ src/libpolarssl/padlock.h | 108 ++ src/libpolarssl/pbkdf2.c | 60 + src/libpolarssl/pbkdf2.h | 82 + src/libpolarssl/pem.c | 355 ++++ src/libpolarssl/pem.h | 105 ++ src/libpolarssl/pkcs11.c | 238 +++ src/libpolarssl/pkcs11.h | 161 ++ src/libpolarssl/pkcs12.c | 330 ++++ src/libpolarssl/pkcs12.h | 131 ++ src/libpolarssl/pkcs5.c | 415 +++++ src/libpolarssl/pkcs5.h | 122 ++ src/libpolarssl/rsa.c | 1466 +++++++++++++++ src/libpolarssl/rsa.h | 597 ++++++ src/libpolarssl/sha1.c | 624 +++++++ src/libpolarssl/sha1.h | 180 ++ src/libpolarssl/sha2.c | 705 +++++++ src/libpolarssl/sha2.h | 188 ++ src/libpolarssl/sha4.c | 760 ++++++++ src/libpolarssl/sha4.h | 186 ++ src/libpolarssl/ssl.h | 1140 ++++++++++++ src/libpolarssl/ssl_cache.c | 221 +++ src/libpolarssl/ssl_cache.h | 119 ++ src/libpolarssl/ssl_cli.c | 1386 ++++++++++++++ src/libpolarssl/ssl_srv.c | 1623 ++++++++++++++++ src/libpolarssl/ssl_tls.c | 3991 ++++++++++++++++++++++++++++++++++++++++ src/libpolarssl/timing.c | 312 ++++ src/libpolarssl/timing.h | 75 + src/libpolarssl/version.c | 50 + src/libpolarssl/version.h | 81 + src/libpolarssl/x509.h | 776 ++++++++ src/libpolarssl/x509parse.c | 3809 ++++++++++++++++++++++++++++++++++++++ src/libpolarssl/x509write.c | 1141 ++++++++++++ src/libpolarssl/x509write.h | 309 ++++ src/libpolarssl/xtea.c | 251 +++ src/libpolarssl/xtea.h | 129 ++ src/xstrbuf.c | 69 + src/xstrbuf.h | 43 + 103 files changed, 44234 insertions(+) create mode 100644 Jamfile create mode 100644 Jamrules create mode 100644 crtgen/certgen.sh create mode 100644 crtgen/creds.txt create mode 100644 src/Jamfile create mode 100644 src/fuckme.c create mode 100644 src/libk8clock/Jamfile create mode 100644 src/libk8clock/k8clock.c create mode 100644 src/libk8clock/k8clock.h create mode 100644 src/libpolarssl/Jamfile create mode 100644 src/libpolarssl/aes.c create mode 100644 src/libpolarssl/aes.h create mode 100644 src/libpolarssl/arc4.c create mode 100644 src/libpolarssl/arc4.h create mode 100644 src/libpolarssl/asn1.h create mode 100644 src/libpolarssl/asn1parse.c create mode 100644 src/libpolarssl/asn1write.c create mode 100644 src/libpolarssl/asn1write.h create mode 100644 src/libpolarssl/base64.c create mode 100644 src/libpolarssl/base64.h create mode 100644 src/libpolarssl/bignum.c create mode 100644 src/libpolarssl/bignum.h create mode 100644 src/libpolarssl/blowfish.c create mode 100644 src/libpolarssl/blowfish.h create mode 100644 src/libpolarssl/bn_mul.h create mode 100644 src/libpolarssl/camellia.c create mode 100644 src/libpolarssl/camellia.h create mode 100644 src/libpolarssl/certs.c create mode 100644 src/libpolarssl/certs.h create mode 100644 src/libpolarssl/cipher.c create mode 100644 src/libpolarssl/cipher.h create mode 100644 src/libpolarssl/cipher_wrap.c create mode 100644 src/libpolarssl/cipher_wrap.h create mode 100644 src/libpolarssl/config.h create mode 100644 src/libpolarssl/ctr_drbg.c create mode 100644 src/libpolarssl/ctr_drbg.h create mode 100644 src/libpolarssl/debug.c create mode 100644 src/libpolarssl/debug.h create mode 100644 src/libpolarssl/des.c create mode 100644 src/libpolarssl/des.h create mode 100644 src/libpolarssl/dhm.c create mode 100644 src/libpolarssl/dhm.h create mode 100644 src/libpolarssl/entropy.c create mode 100644 src/libpolarssl/entropy.h create mode 100644 src/libpolarssl/entropy_poll.c create mode 100644 src/libpolarssl/entropy_poll.h create mode 100644 src/libpolarssl/error.c create mode 100644 src/libpolarssl/error.h create mode 100644 src/libpolarssl/gcm.c create mode 100644 src/libpolarssl/gcm.h create mode 100644 src/libpolarssl/havege.c create mode 100644 src/libpolarssl/havege.h create mode 100644 src/libpolarssl/md.c create mode 100644 src/libpolarssl/md.h create mode 100644 src/libpolarssl/md2.c create mode 100644 src/libpolarssl/md2.h create mode 100644 src/libpolarssl/md4.c create mode 100644 src/libpolarssl/md4.h create mode 100644 src/libpolarssl/md5.c create mode 100644 src/libpolarssl/md5.h create mode 100644 src/libpolarssl/md_wrap.c create mode 100644 src/libpolarssl/md_wrap.h create mode 100644 src/libpolarssl/net.c create mode 100644 src/libpolarssl/net.h create mode 100644 src/libpolarssl/openssl.h create mode 100644 src/libpolarssl/padlock.c create mode 100644 src/libpolarssl/padlock.h create mode 100644 src/libpolarssl/pbkdf2.c create mode 100644 src/libpolarssl/pbkdf2.h create mode 100644 src/libpolarssl/pem.c create mode 100644 src/libpolarssl/pem.h create mode 100644 src/libpolarssl/pkcs11.c create mode 100644 src/libpolarssl/pkcs11.h create mode 100644 src/libpolarssl/pkcs12.c create mode 100644 src/libpolarssl/pkcs12.h create mode 100644 src/libpolarssl/pkcs5.c create mode 100644 src/libpolarssl/pkcs5.h create mode 100644 src/libpolarssl/rsa.c create mode 100644 src/libpolarssl/rsa.h create mode 100644 src/libpolarssl/sha1.c create mode 100644 src/libpolarssl/sha1.h create mode 100644 src/libpolarssl/sha2.c create mode 100644 src/libpolarssl/sha2.h create mode 100644 src/libpolarssl/sha4.c create mode 100644 src/libpolarssl/sha4.h create mode 100644 src/libpolarssl/ssl.h create mode 100644 src/libpolarssl/ssl_cache.c create mode 100644 src/libpolarssl/ssl_cache.h create mode 100644 src/libpolarssl/ssl_cli.c create mode 100644 src/libpolarssl/ssl_srv.c create mode 100644 src/libpolarssl/ssl_tls.c create mode 100644 src/libpolarssl/timing.c create mode 100644 src/libpolarssl/timing.h create mode 100644 src/libpolarssl/version.c create mode 100644 src/libpolarssl/version.h create mode 100644 src/libpolarssl/x509.h create mode 100644 src/libpolarssl/x509parse.c create mode 100644 src/libpolarssl/x509write.c create mode 100644 src/libpolarssl/x509write.h create mode 100644 src/libpolarssl/xtea.c create mode 100644 src/libpolarssl/xtea.h create mode 100644 src/xstrbuf.c create mode 100644 src/xstrbuf.h diff --git a/Jamfile b/Jamfile new file mode 100644 index 0000000..92d5e2e --- /dev/null +++ b/Jamfile @@ -0,0 +1,4 @@ +SubDir TOP ; + + +SubInclude TOP src ; diff --git a/Jamrules b/Jamrules new file mode 100644 index 0000000..4e002cc --- /dev/null +++ b/Jamrules @@ -0,0 +1,14 @@ +if ! $(THIS_IS_K8JAM) { + Exit "You need k8jam to build this Download it here: http://repo.or.cz/w/k8jam.git" ; +} +set-profile ; +set-target-locations ; + + +LINKLIBS.all += -lz ; # for PolarSSL + + +softinclude $(TOP)/Jamrules.local ; +softinclude $(TOP)/Jamrules.libs ; +softinclude $(TOP)/Jamrules.install ; +softinclude $(TOP)/Jamrules.push ; diff --git a/crtgen/certgen.sh b/crtgen/certgen.sh new file mode 100644 index 0000000..5c76ca4 --- /dev/null +++ b/crtgen/certgen.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 2999 -nodes +#include +#include +#include +#include +#include + +#include "libpolarssl/config.h" +#include "libpolarssl/entropy.h" +#include "libpolarssl/ctr_drbg.h" +#include "libpolarssl/certs.h" +#include "libpolarssl/x509.h" +#include "libpolarssl/x509write.h" +#include "libpolarssl/ssl.h" +#include "libpolarssl/net.h" +#include "libpolarssl/timing.h" +#include "libpolarssl/rsa.h" + +#include "xstrbuf.h" + + +#define DEBUG_LEVEL 0 + +#define KEY_SIZE (1024) +//#define KEY_SIZE (128) +#define EXPONENT (65537) + + +#define HTTP_RESPONSE \ + "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \ + "

PolarSSL Test Server

\r\n" \ + "

Successful connection using: %s

\r\n" + + +static void my_debug (void *ctx, int level, const char *str) { + if (level < DEBUG_LEVEL) { + fprintf((FILE *)ctx, "%s", str); + fflush((FILE *)ctx); + } +} + + +static int gen_cert (const char *hostname, x509_cert *srvcert, rsa_context *rsa) { + x509_raw graw; + //509_cert gcert; + char *hbuf = malloc(strlen(hostname)+8192); + int res; + // + /* + fprintf(stderr, "SSL: generating the RSA key [%d-bit]...\n", KEY_SIZE); + rsa_init(&rsa_key, RSA_PKCS_V15, 0); + if ((ret = rsa_gen_key(&rsa_key, ctr_drbg_random, &ctr_drbg, KEY_SIZE, EXPONENT)) != 0) { + fprintf(stderr, "FUCKED: rsa_gen_key returned %d\n", ret); + goto exit; + } + */ + // + /* + sprintf(hbuf, "certs/key.%s.pem", hostname); + res = x509write_keyfile(rsa, hbuf, X509_OUTPUT_PEM); + if (res != 0) { fprintf(stderr, "SHIT: x509write_keyfile=%d\n", res); } + */ + x509write_init_raw(&graw); + // + fprintf(stderr, "SSL: generating the certificate...\n"); + sprintf(hbuf, "CN=%s", hostname); + // + fprintf(stderr, "SSL: x509write_add_pubkey()\n"); + res = x509write_add_pubkey(&graw, rsa); + if (res != 0) { fprintf(stderr, "SHIT: x509write_add_pubkey=%d\n", res); goto error; } + + fprintf(stderr, "SSL: x509write_copy_issuer()\n"); + res = x509write_copy_issuer(&graw, srvcert); + if (res != 0) { fprintf(stderr, "SHIT: x509write_copy_issuer=%d\n", res); goto error; } + + fprintf(stderr, "SSL: x509write_add_subject()\n"); + res = x509write_add_subject(&graw, (unsigned char *)hbuf); + if (res != 0) { fprintf(stderr, "SHIT: x509write_add_subject=%d\n", res); goto error; } + + fprintf(stderr, "SSL: x509write_add_validity()\n"); + res = x509write_add_validity(&graw, (unsigned char *)"2013-01-01 12:00:00", (unsigned char *)"2014-01-01 12:00:00"); + if (res != 0) { fprintf(stderr, "SHIT: x509write_add_validity=%d\n", res); goto error; } + + //fprintf(stderr, "SSL: x509write_create_selfsign()\n"); + //res = x509write_create_selfsign(&graw, rsa); + //if (res != 0) { fprintf(stderr, "SHIT: x509write_create_selfsign=%d\n", res); goto error; } + + fprintf(stderr, "SSL: x509write_create_sign()\n"); + res = x509write_create_sign(&graw, rsa); + if (res != 0) { fprintf(stderr, "SHIT: x509write_create_sign=%d\n", res); goto error; } + +/* + fprintf(stderr, "SSL: x509parse_crt_der()\n"); + res = x509parse_crt_der(&gcert, (const unsigned char *)graw.raw.data, graw.raw.len); + if (res != 0) { fprintf(stderr, "SHIT: x509parse_crt_der=%d\n", res); goto error; } +*/ + + sprintf(hbuf, "certs/cert.%s.pem", hostname); + fprintf(stderr, "SSL: x509write_crtfile()\n"); + res = x509write_crtfile(&graw, hbuf, X509_OUTPUT_PEM); + if (res != 0) { fprintf(stderr, "SHIT: x509write_crtfile=%d\n", res); goto error; } + + fprintf(stderr, "SSL: x509write_free_raw()\n"); + x509write_free_raw(&graw); + //res = x509write_crtfile(&gcert, hbuf, X509_OUTPUT_PEM); + //if (res != 0) { fprintf(stderr, "SHIT: x509write_crtfile=%d\n", res); } + // + //x509write_init_raw( &cert ); + //x509write_add_pubkey( &cert, rsa ); + //x509write_add_subject( &cert, "CN='localhost'" ); + //x509write_add_validity( &cert, "2007-09-06 17:00:32", "2010-09-06 17:00:32" ); + //x509write_create_selfsign( &cert, rsa ); + //x509write_crtfile( &cert, "cert.der", X509_OUTPUT_DER ); + //x509write_crtfile( &cert, "cert.pem", X509_OUTPUT_PEM ); + //x509write_free_raw( &cert ); + return 0; +error: + free(hbuf); + x509write_free_raw(&graw); + return -1; +} + + +int main (int argc, char *argv[]) { + int ret, len; + int listen_fd; + int client_fd = -1; + unsigned char buf[1024], *wpos; + const char *pers = "fuckme"; + // + entropy_context entropy; + ctr_drbg_context ctr_drbg; + x509_cert srvcert; + rsa_context rsa; + ssl_context ssl; + // + signal(SIGCHLD, SIG_IGN); + // + entropy_init(&entropy); + if ((ret = ctr_drbg_init(&ctr_drbg, entropy_func, &entropy, (const unsigned char *)pers, strlen(pers))) != 0) { + fprintf(stderr, "FUCKED: ctr_drbg_init returned %d\n", ret); + goto exit; + } + // + rsa_init(&rsa, RSA_PKCS_V15, 0); + ret = x509parse_keyfile(&rsa, "certs/key.pem", NULL); + if (ret != 0) { + fprintf(stderr, "FUCKED: x509parse_key returned %d\n", ret); + goto exit; + } + // + memset(&srvcert, 0, sizeof(srvcert)); + ret = x509parse_crtfile(&srvcert, "certs/cert.pem"); + if (ret != 0) { + fprintf(stderr, "FUCKED: x509parse_crt returned %d\n", ret); + goto exit; + } + fprintf(stderr, "cert.pem loaded\n"); + // + if (access("certs/cert.localhost.pem", R_OK) != 0) { + if (gen_cert("localhost", &srvcert, &rsa) != 0) { + fprintf(stderr, "FUCKED: can't generate certificate for localhost!\n"); + goto exit; + } + } + // + ret = x509parse_crtfile(&srvcert, "certs/cert.localhost.pem"); + if (ret != 0) { + fprintf(stderr, "FUCKED: x509parse_crt returned %d\n", ret); + goto exit; + } + fprintf(stderr, "cert.localhost.pem loaded\n"); + // + if ((ret = pssl_net_bind(&listen_fd, NULL, 4433)) != 0) { + fprintf(stderr, "FUCKED: pssl_net_bind returned %d\n", ret); + goto exit; + } + // + for (;;) { + pid_t pid; + xstrbuf_t hdrs; + // + memset(&ssl, 0, sizeof(ssl)); + if ((ret = pssl_net_accept(listen_fd, &client_fd, NULL)) != 0) { + fprintf(stderr, "FUCKED: pssl_net_accept returned %d\n", ret); + goto exit; + } + pid = fork(); + if (pid < 0) { + fprintf(stderr, "FUCKED: fork returned %d\n", pid); + goto exit; + } + if (pid != 0) { + // parent + if ((ret = ctr_drbg_reseed(&ctr_drbg, (const unsigned char *)"parent", 6)) != 0) { + fprintf(stderr, "FUCKED: ctr_drbg_reseed returned %d\n", ret); + goto exit; + } + close(client_fd); + continue; + } + // child + close(listen_fd); + // + if ((ret = ctr_drbg_reseed(&ctr_drbg, (const unsigned char *)"child", 5)) != 0) { + fprintf(stderr, "FUCKED: ctr_drbg_reseed returned %d\n", ret); + goto exit; + } + if ((ret = ssl_init(&ssl)) != 0) { + fprintf(stderr, "FUCKED: ssl_init returned %d\n\n", ret); + goto exit; + } + ssl_set_endpoint(&ssl, SSL_IS_SERVER); + ssl_set_authmode(&ssl, SSL_VERIFY_NONE); + ssl_set_rng(&ssl, ctr_drbg_random, &ctr_drbg); + ssl_set_dbg(&ssl, my_debug, stdout); + ssl_set_bio(&ssl, pssl_net_recv, &client_fd, pssl_net_send, &client_fd); + if (srvcert.next == NULL) { + fprintf(stderr, "SSL: we DON'T have two certificates!\n"); + goto exit; + } + ssl_set_ca_chain(&ssl, &srvcert, NULL, NULL); + ssl_set_own_cert(&ssl, srvcert.next, &rsa); + // + fprintf(stderr, "SSL: performing handshake...\n"); + while ((ret = ssl_handshake(&ssl)) != 0) { + if (ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE) { + fprintf(stderr, "FUCKED: ssl_handshake returned %d\n", ret); + goto exit; + } + } + // + fprintf(stderr, "SSL: reading headers from client...\n"); + xstrbuf_init(&hdrs); + for (;;) { + char c; + ret = ssl_read(&ssl, (void *)&c, 1); + if (ret == POLARSSL_ERR_NET_WANT_READ || ret == POLARSSL_ERR_NET_WANT_WRITE) continue; + if (ret <= 0) { + switch (ret) { + case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY: + fprintf(stderr, "SSL: connection was closed gracefully\n"); + break; + case POLARSSL_ERR_NET_CONN_RESET: + fprintf(stderr, "SSL: connection was reset by peer\n"); + break; + default: + fprintf(stderr, "SSL: ssl_read returned %d\n", ret); + break; + } + break; + } + xstrbuf_addc(&hdrs, c); + if (hdrs.used >= 2 && hdrs.data[hdrs.used-1] == '\n') { + if (hdrs.data[hdrs.used-2] == '\n') break; // headers complete + if (hdrs.data[hdrs.used-2] == '\r' && hdrs.used >= 3 && hdrs.data[hdrs.used-3] == '\n') break; // headers complete + } + } + fprintf(stderr, "=== HEADERS ===\n%s===\n", hdrs.data); + xstrbuf_free(&hdrs); + // + fprintf(stderr, "SSL: writing to client...\n"); + len = sprintf((char *)buf, HTTP_RESPONSE, ssl_get_ciphersuite(&ssl)); + wpos = buf; + while (len > 0) { + while ((ret = ssl_write(&ssl, wpos, len)) <= 0) { + if (ret == POLARSSL_ERR_NET_CONN_RESET) { + fprintf(stderr, "SSL: peer closed the connection\n"); + goto exit; + } + if (ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE) { + fprintf(stderr, "SSL: ssl_write returned %d\n", ret); + goto exit; + } + } + len -= ret; + wpos += ret; + } + ssl_close_notify(&ssl); + goto exit; + } +exit: + pssl_net_close(client_fd); + x509_free(&srvcert); + rsa_free(&rsa); + ssl_free(&ssl); + // + return ret; +} diff --git a/src/libk8clock/Jamfile b/src/libk8clock/Jamfile new file mode 100644 index 0000000..273ad56 --- /dev/null +++ b/src/libk8clock/Jamfile @@ -0,0 +1,6 @@ +SubDir TOP src libk8clock ; + + +Library libk8clock.a : + k8clock.c +; diff --git a/src/libk8clock/k8clock.c b/src/libk8clock/k8clock.c new file mode 100644 index 0000000..c8eda1c --- /dev/null +++ b/src/libk8clock/k8clock.c @@ -0,0 +1,113 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * Understanding is not required. Only obedience. + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://www.wtfpl.net/txt/copying/ for more details. + */ +#include +#include +#include +#include + +#include "k8clock.h" + + +k8clock_type k8clock_initialized = K8CLOCK_ERROR; +k8clock_t clk; + + +#ifndef CLOCK_MONOTONIC_RAW +# define K8CLOCK_CLOCK_TYPE CLOCK_MONOTONIC_RAW +#else +# define K8CLOCK_CLOCK_TYPE CLOCK_MONOTONIC +#endif + + +static k8clock_type k8clock_check_source (void) { + FILE *fl = fopen("/sys/devices/system/clocksource/clocksource0/current_clocksource", "r"); + char buf[128]; + if (fl == NULL) { + fprintf(stderr, "WARNING: can't determine clock source!\n"); + return K8CLOCK_OTHER; + } + memset(buf, 0, sizeof(buf)); + if (fgets(buf, sizeof(buf)-1, fl) == NULL) { + fclose(fl); + fprintf(stderr, "WARNING: can't determine clock source!\n"); + return K8CLOCK_OTHER; + } + fclose(fl); + while (buf[0] && isspace(buf[strlen(buf)-1])) buf[strlen(buf)-1] = 0; + //fprintf(stderr, "clock source: %s\n", buf); + return (strcasecmp(buf, "hpet") == 0 ? K8CLOCK_HPET : K8CLOCK_OTHER); +} + + +__attribute__((constructor)) static void k8clock_ctor (void) { + if (k8clock_initialized == K8CLOCK_ERROR) { + struct timespec cres; + k8clock_initialized = k8clock_check_source(); + if (clock_getres(K8CLOCK_CLOCK_TYPE, &cres) != 0) { + fprintf(stderr, "ERROR: can't get clock resolution!\n"); + k8clock_initialized = K8CLOCK_ERROR; + return; + } + //fprintf(stderr, "CLOCK_MONOTONIC: %ld:%ld\n", cres.tv_sec, cres.tv_nsec); + if (cres.tv_sec > 0 || cres.tv_nsec > (long)1000000*10 /*10 ms*/) { + fprintf(stderr, "ERROR: real-time clock resolution is too low!\n"); + k8clock_initialized = K8CLOCK_ERROR; + return; + } + k8clock_init(&clk); + } +} + + +void k8clock_init (k8clock_t *clk) { + if (clk != NULL && k8clock_initialized != K8CLOCK_ERROR) { + if (clock_gettime(K8CLOCK_CLOCK_TYPE, &clk->stt) != 0) { + fprintf(stderr, "ERROR: can't get real-time clock value!\n"); + } + } +} + + +uint64_t k8clock_ms (k8clock_t *clk) { + if (clk != NULL && k8clock_initialized != K8CLOCK_ERROR) { + struct timespec ts; + if (clock_gettime(K8CLOCK_CLOCK_TYPE, &ts) != 0) { + fprintf(stderr, "ERROR: can't get real-time clock value!\n"); + return 0; + } + // ah, ignore nanoseconds in clk->stt here: we need only 'differential' time, and it can start with something weird + return ((int64_t)(ts.tv_sec-clk->stt.tv_sec))*1000+(ts.tv_nsec-clk->stt.tv_nsec)/1000000+1; + } + return 0; +} + + +uint64_t k8clock_micro (k8clock_t *clk) { + if (clk != NULL && k8clock_initialized != K8CLOCK_ERROR) { + struct timespec ts; + if (clock_gettime(K8CLOCK_CLOCK_TYPE, &ts) != 0) { + fprintf(stderr, "ERROR: can't get real-time clock value!\n"); + return 0; + } + // ah, ignore nanoseconds in clk->stt here: we need only 'differential' time, and it can start with something weird + return ((int64_t)(ts.tv_sec-clk->stt.tv_sec))*1000000+(ts.tv_nsec-clk->stt.tv_nsec)/1000+1; + } + return 0; +} + + +uint64_t k8clock (void) { + return k8clock_ms(&clk); +} + + +uint64_t k8clockmicro (void) { + return k8clock_micro(&clk); +} diff --git a/src/libk8clock/k8clock.h b/src/libk8clock/k8clock.h new file mode 100644 index 0000000..57e2426 --- /dev/null +++ b/src/libk8clock/k8clock.h @@ -0,0 +1,47 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * Understanding is not required. Only obedience. + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://www.wtfpl.net/txt/copying/ for more details. + */ +#ifndef _K8CLOCK_H_ +#define _K8CLOCK_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + + +typedef enum { + K8CLOCK_ERROR = -1, + K8CLOCK_HPET = 0, + K8CLOCK_OTHER = 1 +} k8clock_type; + + +typedef struct { + struct timespec stt; +} k8clock_t; + + +extern k8clock_type k8clock_initialized; + + +extern void k8clock_init (k8clock_t *clk); +extern uint64_t k8clock_ms (k8clock_t *clk); // milliseconds; (0: no timer available) +extern uint64_t k8clock_micro (k8clock_t *clk); // microseconds; (0: no timer available) + +extern uint64_t k8clock (void); // milliseconds; (0: no timer available) +extern uint64_t k8clockmicro (void); // microseconds; (0: no timer available) + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/libpolarssl/Jamfile b/src/libpolarssl/Jamfile new file mode 100644 index 0000000..8253f86 --- /dev/null +++ b/src/libpolarssl/Jamfile @@ -0,0 +1,50 @@ +SubDir TOP src libpolarssl ; + + +Library libpolarssl.a : + aes.c + arc4.c + asn1parse.c + asn1write.c + base64.c + bignum.c + blowfish.c + camellia.c + certs.c + cipher.c + cipher_wrap.c + ctr_drbg.c + debug.c + des.c + dhm.c + entropy.c + entropy_poll.c + error.c + gcm.c + havege.c + md.c + md_wrap.c + md2.c + md4.c + md5.c + net.c + padlock.c + pbkdf2.c + pem.c + pkcs5.c + pkcs11.c + pkcs12.c + rsa.c + sha1.c + sha2.c + sha4.c + ssl_cache.c + ssl_cli.c + ssl_srv.c + ssl_tls.c + timing.c + version.c + x509parse.c + x509write.c + xtea.c +; diff --git a/src/libpolarssl/aes.c b/src/libpolarssl/aes.c new file mode 100644 index 0000000..2dae019 --- /dev/null +++ b/src/libpolarssl/aes.c @@ -0,0 +1,1352 @@ +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#include "config.h" + +#if defined(POLARSSL_AES_C) + +#include "aes.h" +#if defined(POLARSSL_PADLOCK_C) +#include "padlock.h" +#endif + +#if !defined(POLARSSL_AES_ALT) + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ +} +#endif + +#if defined(POLARSSL_PADLOCK_C) && \ + ( defined(POLARSSL_HAVE_X86) || defined(PADLOCK_ALIGN16) ) +static int aes_padlock_ace = -1; +#endif + +#if defined(POLARSSL_AES_ROM_TABLES) +/* + * Forward S-box + */ +static const unsigned char FSb[256] = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, + 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, + 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, + 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, + 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, + 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, + 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, + 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, + 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, + 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, + 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, + 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + +/* + * Forward tables + */ +#define FT \ +\ + V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \ + V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \ + V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \ + V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \ + V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \ + V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \ + V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \ + V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \ + V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \ + V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \ + V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \ + V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \ + V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \ + V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \ + V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \ + V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \ + V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \ + V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \ + V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \ + V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \ + V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \ + V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \ + V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \ + V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \ + V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \ + V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \ + V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \ + V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \ + V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \ + V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \ + V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \ + V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \ + V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \ + V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \ + V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \ + V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \ + V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \ + V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \ + V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \ + V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \ + V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \ + V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \ + V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \ + V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \ + V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \ + V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \ + V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \ + V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \ + V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \ + V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \ + V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \ + V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \ + V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \ + V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \ + V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \ + V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \ + V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \ + V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \ + V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \ + V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \ + V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \ + V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \ + V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \ + V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32_t FT0[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32_t FT1[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32_t FT2[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32_t FT3[256] = { FT }; +#undef V + +#undef FT + +/* + * Reverse S-box + */ +static const unsigned char RSb[256] = +{ + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, + 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, + 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, + 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, + 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, + 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, + 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, + 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, + 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, + 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, + 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, + 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D +}; + +/* + * Reverse tables + */ +#define RT \ +\ + V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \ + V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \ + V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \ + V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \ + V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \ + V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \ + V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \ + V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \ + V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \ + V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \ + V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \ + V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \ + V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \ + V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \ + V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \ + V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \ + V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \ + V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \ + V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \ + V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \ + V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \ + V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \ + V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \ + V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \ + V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \ + V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \ + V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \ + V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \ + V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \ + V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \ + V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \ + V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \ + V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \ + V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \ + V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \ + V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \ + V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \ + V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \ + V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \ + V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \ + V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \ + V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \ + V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \ + V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \ + V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \ + V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \ + V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \ + V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \ + V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \ + V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \ + V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \ + V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \ + V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \ + V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \ + V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \ + V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \ + V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \ + V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \ + V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \ + V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \ + V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \ + V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \ + V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \ + V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32_t RT0[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32_t RT1[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32_t RT2[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32_t RT3[256] = { RT }; +#undef V + +#undef RT + +/* + * Round constants + */ +static const uint32_t RCON[10] = +{ + 0x00000001, 0x00000002, 0x00000004, 0x00000008, + 0x00000010, 0x00000020, 0x00000040, 0x00000080, + 0x0000001B, 0x00000036 +}; + +#else + +/* + * Forward S-box & tables + */ +static unsigned char FSb[256]; +static uint32_t FT0[256]; +static uint32_t FT1[256]; +static uint32_t FT2[256]; +static uint32_t FT3[256]; + +/* + * Reverse S-box & tables + */ +static unsigned char RSb[256]; +static uint32_t RT0[256]; +static uint32_t RT1[256]; +static uint32_t RT2[256]; +static uint32_t RT3[256]; + +/* + * Round constants + */ +static uint32_t RCON[10]; + +/* + * Tables generation code + */ +#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) +#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) +#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) + +static int aes_init_done = 0; + +static void aes_gen_tables( void ) +{ + int i, x, y, z; + int pow[256]; + int log[256]; + + /* + * compute pow and log tables over GF(2^8) + */ + for( i = 0, x = 1; i < 256; i++ ) + { + pow[i] = x; + log[x] = i; + x = ( x ^ XTIME( x ) ) & 0xFF; + } + + /* + * calculate the round constants + */ + for( i = 0, x = 1; i < 10; i++ ) + { + RCON[i] = (uint32_t) x; + x = XTIME( x ) & 0xFF; + } + + /* + * generate the forward and reverse S-boxes + */ + FSb[0x00] = 0x63; + RSb[0x63] = 0x00; + + for( i = 1; i < 256; i++ ) + { + x = pow[255 - log[i]]; + + y = x; y = ( (y << 1) | (y >> 7) ) & 0xFF; + x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; + x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; + x ^= y; y = ( (y << 1) | (y >> 7) ) & 0xFF; + x ^= y ^ 0x63; + + FSb[i] = (unsigned char) x; + RSb[x] = (unsigned char) i; + } + + /* + * generate the forward and reverse tables + */ + for( i = 0; i < 256; i++ ) + { + x = FSb[i]; + y = XTIME( x ) & 0xFF; + z = ( y ^ x ) & 0xFF; + + FT0[i] = ( (uint32_t) y ) ^ + ( (uint32_t) x << 8 ) ^ + ( (uint32_t) x << 16 ) ^ + ( (uint32_t) z << 24 ); + + FT1[i] = ROTL8( FT0[i] ); + FT2[i] = ROTL8( FT1[i] ); + FT3[i] = ROTL8( FT2[i] ); + + x = RSb[i]; + + RT0[i] = ( (uint32_t) MUL( 0x0E, x ) ) ^ + ( (uint32_t) MUL( 0x09, x ) << 8 ) ^ + ( (uint32_t) MUL( 0x0D, x ) << 16 ) ^ + ( (uint32_t) MUL( 0x0B, x ) << 24 ); + + RT1[i] = ROTL8( RT0[i] ); + RT2[i] = ROTL8( RT1[i] ); + RT3[i] = ROTL8( RT2[i] ); + } +} + +#endif + +/* + * AES key schedule (encryption) + */ +int aes_setkey_enc( aes_context *ctx, const unsigned char *key, unsigned int keysize ) +{ + unsigned int i; + uint32_t *RK; + +#if !defined(POLARSSL_AES_ROM_TABLES) + if( aes_init_done == 0 ) + { + aes_gen_tables(); + aes_init_done = 1; + + } +#endif + + switch( keysize ) + { + case 128: ctx->nr = 10; break; + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; + default : return( POLARSSL_ERR_AES_INVALID_KEY_LENGTH ); + } + +#if defined(POLARSSL_PADLOCK_C) && defined(PADLOCK_ALIGN16) + if( aes_padlock_ace == -1 ) + aes_padlock_ace = padlock_supports( PADLOCK_ACE ); + + if( aes_padlock_ace ) + ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf ); + else +#endif + ctx->rk = RK = ctx->buf; + + for( i = 0; i < (keysize >> 5); i++ ) + { + GET_UINT32_LE( RK[i], key, i << 2 ); + } + + switch( ctx->nr ) + { + case 10: + + for( i = 0; i < 10; i++, RK += 4 ) + { + RK[4] = RK[0] ^ RCON[i] ^ + ( (uint32_t) FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[3] ) & 0xFF ] << 24 ); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + break; + + case 12: + + for( i = 0; i < 8; i++, RK += 6 ) + { + RK[6] = RK[0] ^ RCON[i] ^ + ( (uint32_t) FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[5] ) & 0xFF ] << 24 ); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + break; + + case 14: + + for( i = 0; i < 7; i++, RK += 8 ) + { + RK[8] = RK[0] ^ RCON[i] ^ + ( (uint32_t) FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[7] ) & 0xFF ] << 24 ); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ + ( (uint32_t) FSb[ ( RK[11] ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 ); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + break; + + default: + + break; + } + + return( 0 ); +} + +/* + * AES key schedule (decryption) + */ +int aes_setkey_dec( aes_context *ctx, const unsigned char *key, unsigned int keysize ) +{ + int i, j; + aes_context cty; + uint32_t *RK; + uint32_t *SK; + int ret; + + switch( keysize ) + { + case 128: ctx->nr = 10; break; + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; + default : return( POLARSSL_ERR_AES_INVALID_KEY_LENGTH ); + } + +#if defined(POLARSSL_PADLOCK_C) && defined(PADLOCK_ALIGN16) + if( aes_padlock_ace == -1 ) + aes_padlock_ace = padlock_supports( PADLOCK_ACE ); + + if( aes_padlock_ace ) + ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf ); + else +#endif + ctx->rk = RK = ctx->buf; + + ret = aes_setkey_enc( &cty, key, keysize ); + if( ret != 0 ) + return( ret ); + + SK = cty.rk + cty.nr * 4; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 ) + { + for( j = 0; j < 4; j++, SK++ ) + { + *RK++ = RT0[ FSb[ ( *SK ) & 0xFF ] ] ^ + RT1[ FSb[ ( *SK >> 8 ) & 0xFF ] ] ^ + RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^ + RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ]; + } + } + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + memset( &cty, 0, sizeof( aes_context ) ); + + return( 0 ); +} + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ + FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y3 >> 24 ) & 0xFF ]; \ + \ + X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ + FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y0 >> 24 ) & 0xFF ]; \ + \ + X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ + FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y1 >> 24 ) & 0xFF ]; \ + \ + X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ + FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y2 >> 24 ) & 0xFF ]; \ +} + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ + RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y1 >> 24 ) & 0xFF ]; \ + \ + X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ + RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y2 >> 24 ) & 0xFF ]; \ + \ + X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ + RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y3 >> 24 ) & 0xFF ]; \ + \ + X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ + RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y0 >> 24 ) & 0xFF ]; \ +} + +/* + * AES-ECB block encryption/decryption + */ +int aes_crypt_ecb( aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + +#if defined(POLARSSL_PADLOCK_C) && defined(POLARSSL_HAVE_X86) + if( aes_padlock_ace ) + { + if( padlock_xcryptecb( ctx, mode, input, output ) == 0 ) + return( 0 ); + + // If padlock data misaligned, we just fall back to + // unaccelerated mode + // + } +#endif + + RK = ctx->rk; + + GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; + GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; + GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; + GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; + + if( mode == AES_DECRYPT ) + { + for( i = (ctx->nr >> 1) - 1; i > 0; i-- ) + { + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y0 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y1 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y2 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y3 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + } + else /* AES_ENCRYPT */ + { + for( i = (ctx->nr >> 1) - 1; i > 0; i-- ) + { + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y0 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y1 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y2 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y3 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + } + + PUT_UINT32_LE( X0, output, 0 ); + PUT_UINT32_LE( X1, output, 4 ); + PUT_UINT32_LE( X2, output, 8 ); + PUT_UINT32_LE( X3, output, 12 ); + + return( 0 ); +} + +/* + * AES-CBC buffer encryption/decryption + */ +int aes_crypt_cbc( aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + + if( length % 16 ) + return( POLARSSL_ERR_AES_INVALID_INPUT_LENGTH ); + +#if defined(POLARSSL_PADLOCK_C) && defined(POLARSSL_HAVE_X86) + if( aes_padlock_ace ) + { + if( padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 ) + return( 0 ); + + // If padlock data misaligned, we just fall back to + // unaccelerated mode + // + } +#endif + + if( mode == AES_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + aes_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + aes_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + + return( 0 ); +} + +#if defined(POLARSSL_CIPHER_MODE_CFB) +/* + * AES-CFB128 buffer encryption/decryption + */ +int aes_crypt_cfb128( aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == AES_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = (n + 1) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = (n + 1) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /*POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +/* + * AES-CTR buffer encryption/decryption + */ +int aes_crypt_ctr( aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + aes_crypt_ecb( ctx, AES_ENCRYPT, nonce_counter, stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = (n + 1) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* POLARSSL_CIPHER_MODE_CTR */ +#endif /* !POLARSSL_AES_ALT */ + +#if defined(POLARSSL_SELF_TEST) + +#include + +/* + * AES test vectors from: + * + * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip + */ +static const unsigned char aes_test_ecb_dec[3][16] = +{ + { 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58, + 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 }, + { 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2, + 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 }, + { 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D, + 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE } +}; + +static const unsigned char aes_test_ecb_enc[3][16] = +{ + { 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73, + 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F }, + { 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11, + 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 }, + { 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D, + 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 } +}; + +static const unsigned char aes_test_cbc_dec[3][16] = +{ + { 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73, + 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 }, + { 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75, + 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B }, + { 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75, + 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 } +}; + +static const unsigned char aes_test_cbc_enc[3][16] = +{ + { 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84, + 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D }, + { 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB, + 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 }, + { 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5, + 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 } +}; + +#if defined(POLARSSL_CIPHER_MODE_CFB) +/* + * AES-CFB128 test vectors from: + * + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + */ +static const unsigned char aes_test_cfb128_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char aes_test_cfb128_iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + +static const unsigned char aes_test_cfb128_pt[64] = +{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const unsigned char aes_test_cfb128_ct[3][64] = +{ + { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, + 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, + 0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F, + 0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B, + 0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40, + 0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF, + 0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E, + 0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 }, + { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, + 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, + 0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21, + 0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A, + 0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1, + 0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9, + 0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0, + 0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF }, + { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, + 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, + 0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8, + 0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B, + 0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92, + 0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9, + 0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8, + 0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 } +}; +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +/* + * AES-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc3686.html + */ + +static const unsigned char aes_test_ctr_key[3][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char aes_test_ctr_nonce_counter[3][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char aes_test_ctr_pt[3][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char aes_test_ctr_ct[3][48] = +{ + { 0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79, + 0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8 }, + { 0x51, 0x04, 0xA1, 0x06, 0x16, 0x8A, 0x72, 0xD9, + 0x79, 0x0D, 0x41, 0xEE, 0x8E, 0xDA, 0xD3, 0x88, + 0xEB, 0x2E, 0x1E, 0xFC, 0x46, 0xDA, 0x57, 0xC8, + 0xFC, 0xE6, 0x30, 0xDF, 0x91, 0x41, 0xBE, 0x28 }, + { 0xC1, 0xCF, 0x48, 0xA8, 0x9F, 0x2F, 0xFD, 0xD9, + 0xCF, 0x46, 0x52, 0xE9, 0xEF, 0xDB, 0x72, 0xD7, + 0x45, 0x40, 0xA4, 0x2B, 0xDE, 0x6D, 0x78, 0x36, + 0xD5, 0x9A, 0x5C, 0xEA, 0xAE, 0xF3, 0x10, 0x53, + 0x25, 0xB2, 0x07, 0x2F } +}; + +static const int aes_test_ctr_len[3] = + { 16, 32, 36 }; +#endif /* POLARSSL_CIPHER_MODE_CTR */ + +/* + * Checkup routine + */ +int aes_self_test( int verbose ) +{ + int i, j, u, v; + unsigned char key[32]; + unsigned char buf[64]; + unsigned char prv[16]; + unsigned char iv[16]; +#if defined(POLARSSL_CIPHER_MODE_CTR) || defined(POLARSSL_CIPHER_MODE_CFB) + size_t offset; +#endif +#if defined(POLARSSL_CIPHER_MODE_CTR) + int len; + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + aes_context ctx; + + memset( key, 0, 32 ); + + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " AES-ECB-%3d (%s): ", 128 + u * 64, + ( v == AES_DECRYPT ) ? "dec" : "enc" ); + + memset( buf, 0, 16 ); + + if( v == AES_DECRYPT ) + { + aes_setkey_dec( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + aes_crypt_ecb( &ctx, v, buf, buf ); + + if( memcmp( buf, aes_test_ecb_dec[u], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + aes_crypt_ecb( &ctx, v, buf, buf ); + + if( memcmp( buf, aes_test_ecb_enc[u], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " AES-CBC-%3d (%s): ", 128 + u * 64, + ( v == AES_DECRYPT ) ? "dec" : "enc" ); + + memset( iv , 0, 16 ); + memset( prv, 0, 16 ); + memset( buf, 0, 16 ); + + if( v == AES_DECRYPT ) + { + aes_setkey_dec( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); + + if( memcmp( buf, aes_test_cbc_dec[u], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[16]; + + aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); + + memcpy( tmp, prv, 16 ); + memcpy( prv, buf, 16 ); + memcpy( buf, tmp, 16 ); + } + + if( memcmp( prv, aes_test_cbc_enc[u], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + +#if defined(POLARSSL_CIPHER_MODE_CFB) + /* + * CFB128 mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " AES-CFB128-%3d (%s): ", 128 + u * 64, + ( v == AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, aes_test_cfb128_iv, 16 ); + memcpy( key, aes_test_cfb128_key[u], 16 + u * 8 ); + + offset = 0; + aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + if( v == AES_DECRYPT ) + { + memcpy( buf, aes_test_cfb128_ct[u], 64 ); + aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); + + if( memcmp( buf, aes_test_cfb128_pt, 64 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + memcpy( buf, aes_test_cfb128_pt, 64 ); + aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); + + if( memcmp( buf, aes_test_cfb128_ct[u], 64 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " AES-CTR-128 (%s): ", + ( v == AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( nonce_counter, aes_test_ctr_nonce_counter[u], 16 ); + memcpy( key, aes_test_ctr_key[u], 16 ); + + offset = 0; + aes_setkey_enc( &ctx, key, 128 ); + + if( v == AES_DECRYPT ) + { + len = aes_test_ctr_len[u]; + memcpy( buf, aes_test_ctr_ct[u], len ); + + aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, buf, buf ); + + if( memcmp( buf, aes_test_ctr_pt[u], len ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + len = aes_test_ctr_len[u]; + memcpy( buf, aes_test_ctr_pt[u], len ); + + aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, buf, buf ); + + if( memcmp( buf, aes_test_ctr_ct[u], len ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); +#endif /* POLARSSL_CIPHER_MODE_CTR */ + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/aes.h b/src/libpolarssl/aes.h new file mode 100644 index 0000000..30fdf61 --- /dev/null +++ b/src/libpolarssl/aes.h @@ -0,0 +1,202 @@ +/** + * \file aes.h + * + * \brief AES block cipher + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_AES_H +#define POLARSSL_AES_H + +#include "config.h" + +#include + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define AES_ENCRYPT 1 +#define AES_DECRYPT 0 + +#define POLARSSL_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ +#define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ + +#if !defined(POLARSSL_AES_ALT) +// Regular implementation +// + +/** + * \brief AES context structure + */ +typedef struct +{ + int nr; /*!< number of rounds */ + uint32_t *rk; /*!< AES round keys */ + uint32_t buf[68]; /*!< unaligned data */ +} +aes_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief AES key schedule (encryption) + * + * \param ctx AES context to be initialized + * \param key encryption key + * \param keysize must be 128, 192 or 256 + * + * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH + */ +int aes_setkey_enc( aes_context *ctx, const unsigned char *key, unsigned int keysize ); + +/** + * \brief AES key schedule (decryption) + * + * \param ctx AES context to be initialized + * \param key decryption key + * \param keysize must be 128, 192 or 256 + * + * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH + */ +int aes_setkey_dec( aes_context *ctx, const unsigned char *key, unsigned int keysize ); + +/** + * \brief AES-ECB block encryption/decryption + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int aes_crypt_ecb( aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief AES-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_INPUT_LENGTH + */ +int aes_crypt_cbc( aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief AES-CFB128 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. + * + * both + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int aes_crypt_cfb128( aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief AES-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. + * + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int aes_crypt_ctr( aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_AES_ALT */ +#include "aes_alt.h" +#endif /* POLARSSL_AES_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int aes_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* aes.h */ diff --git a/src/libpolarssl/arc4.c b/src/libpolarssl/arc4.c new file mode 100644 index 0000000..790922a --- /dev/null +++ b/src/libpolarssl/arc4.c @@ -0,0 +1,173 @@ +/* + * An implementation of the ARCFOUR algorithm + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The ARCFOUR algorithm was publicly disclosed on 94/09. + * + * http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0 + */ + +#include "config.h" + +#if defined(POLARSSL_ARC4_C) + +#include "arc4.h" + +#if !defined(POLARSSL_ARC4_ALT) + +/* + * ARC4 key schedule + */ +void arc4_setup( arc4_context *ctx, const unsigned char *key, unsigned int keylen ) +{ + int i, j, a; + unsigned int k; + unsigned char *m; + + ctx->x = 0; + ctx->y = 0; + m = ctx->m; + + for( i = 0; i < 256; i++ ) + m[i] = (unsigned char) i; + + j = k = 0; + + for( i = 0; i < 256; i++, k++ ) + { + if( k >= keylen ) k = 0; + + a = m[i]; + j = ( j + a + key[k] ) & 0xFF; + m[i] = m[j]; + m[j] = (unsigned char) a; + } +} + +/* + * ARC4 cipher function + */ +int arc4_crypt( arc4_context *ctx, size_t length, const unsigned char *input, + unsigned char *output ) +{ + int x, y, a, b; + size_t i; + unsigned char *m; + + x = ctx->x; + y = ctx->y; + m = ctx->m; + + for( i = 0; i < length; i++ ) + { + x = ( x + 1 ) & 0xFF; a = m[x]; + y = ( y + a ) & 0xFF; b = m[y]; + + m[x] = (unsigned char) b; + m[y] = (unsigned char) a; + + output[i] = (unsigned char) + ( input[i] ^ m[(unsigned char)( a + b )] ); + } + + ctx->x = x; + ctx->y = y; + + return( 0 ); +} + +#endif /* !POLARSSL_ARC4_ALT */ + +#if defined(POLARSSL_SELF_TEST) + +#include +#include + +/* + * ARC4 tests vectors as posted by Eric Rescorla in sep. 1994: + * + * http://groups.google.com/group/comp.security.misc/msg/10a300c9d21afca0 + */ +static const unsigned char arc4_test_key[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char arc4_test_pt[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char arc4_test_ct[3][8] = +{ + { 0x75, 0xB7, 0x87, 0x80, 0x99, 0xE0, 0xC5, 0x96 }, + { 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 }, + { 0xDE, 0x18, 0x89, 0x41, 0xA3, 0x37, 0x5D, 0x3A } +}; + +/* + * Checkup routine + */ +int arc4_self_test( int verbose ) +{ + int i; + unsigned char ibuf[8]; + unsigned char obuf[8]; + arc4_context ctx; + + for( i = 0; i < 3; i++ ) + { + if( verbose != 0 ) + printf( " ARC4 test #%d: ", i + 1 ); + + memcpy( ibuf, arc4_test_pt[i], 8 ); + + arc4_setup( &ctx, arc4_test_key[i], 8 ); + arc4_crypt( &ctx, 8, ibuf, obuf ); + + if( memcmp( obuf, arc4_test_ct[i], 8 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/arc4.h b/src/libpolarssl/arc4.h new file mode 100644 index 0000000..1672fa2 --- /dev/null +++ b/src/libpolarssl/arc4.h @@ -0,0 +1,98 @@ +/** + * \file arc4.h + * + * \brief The ARCFOUR stream cipher + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ARC4_H +#define POLARSSL_ARC4_H + +#include "config.h" + +#include + +#if !defined(POLARSSL_ARC4_ALT) +// Regular implementation +// + +/** + * \brief ARC4 context structure + */ +typedef struct +{ + int x; /*!< permutation index */ + int y; /*!< permutation index */ + unsigned char m[256]; /*!< permutation table */ +} +arc4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief ARC4 key schedule + * + * \param ctx ARC4 context to be initialized + * \param key the secret key + * \param keylen length of the key + */ +void arc4_setup( arc4_context *ctx, const unsigned char *key, unsigned int keylen ); + +/** + * \brief ARC4 cipher function + * + * \param ctx ARC4 context + * \param length length of the input data + * \param input buffer holding the input data + * \param output buffer for the output data + * + * \return 0 if successful + */ +int arc4_crypt( arc4_context *ctx, size_t length, const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_ARC4_ALT */ +#include "arc4_alt.h" +#endif /* POLARSSL_ARC4_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int arc4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* arc4.h */ diff --git a/src/libpolarssl/asn1.h b/src/libpolarssl/asn1.h new file mode 100644 index 0000000..893292d --- /dev/null +++ b/src/libpolarssl/asn1.h @@ -0,0 +1,246 @@ +/** + * \file asn1.h + * + * \brief Generic ASN.1 parsing + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ASN1_H +#define POLARSSL_ASN1_H + +#include "config.h" + +#if defined(POLARSSL_BIGNUM_C) +#include "bignum.h" +#endif + +#include + +/** + * \addtogroup asn1_module + * \{ + */ + +/** + * \name ASN1 Error codes + * These error codes are OR'ed to X509 error codes for + * higher error granularity. + * ASN1 is a standard to specify data structures. + * \{ + */ +#define POLARSSL_ERR_ASN1_OUT_OF_DATA -0x0060 /**< Out of data when parsing an ASN1 data structure. */ +#define POLARSSL_ERR_ASN1_UNEXPECTED_TAG -0x0062 /**< ASN1 tag was of an unexpected value. */ +#define POLARSSL_ERR_ASN1_INVALID_LENGTH -0x0064 /**< Error when trying to determine the length or invalid length. */ +#define POLARSSL_ERR_ASN1_LENGTH_MISMATCH -0x0066 /**< Actual length differs from expected length. */ +#define POLARSSL_ERR_ASN1_INVALID_DATA -0x0068 /**< Data is invalid. (not used) */ +#define POLARSSL_ERR_ASN1_MALLOC_FAILED -0x006A /**< Memory allocation failed */ +#define POLARSSL_ERR_ASN1_BUF_TOO_SMALL -0x006C /**< Buffer too small when writing ASN.1 data structure. */ + +/* \} name */ + +/** + * \name DER constants + * These constants comply with DER encoded the ANS1 type tags. + * DER encoding uses hexadecimal representation. + * An example DER sequence is:\n + * - 0x02 -- tag indicating INTEGER + * - 0x01 -- length in octets + * - 0x05 -- value + * Such sequences are typically read into \c ::x509_buf. + * \{ + */ +#define ASN1_BOOLEAN 0x01 +#define ASN1_INTEGER 0x02 +#define ASN1_BIT_STRING 0x03 +#define ASN1_OCTET_STRING 0x04 +#define ASN1_NULL 0x05 +#define ASN1_OID 0x06 +#define ASN1_UTF8_STRING 0x0C +#define ASN1_SEQUENCE 0x10 +#define ASN1_SET 0x11 +#define ASN1_PRINTABLE_STRING 0x13 +#define ASN1_T61_STRING 0x14 +#define ASN1_IA5_STRING 0x16 +#define ASN1_UTC_TIME 0x17 +#define ASN1_GENERALIZED_TIME 0x18 +#define ASN1_UNIVERSAL_STRING 0x1C +#define ASN1_BMP_STRING 0x1E +#define ASN1_PRIMITIVE 0x00 +#define ASN1_CONSTRUCTED 0x20 +#define ASN1_CONTEXT_SPECIFIC 0x80 +/* \} name */ +/* \} addtogroup asn1_module */ + +/** Returns the size of the binary string, without the trailing \\0 */ +#define OID_SIZE(x) (sizeof(x) - 1) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Functions to parse ASN.1 data structures + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef struct _asn1_buf +{ + int tag; /**< ASN1 type, e.g. ASN1_UTF8_STRING. */ + size_t len; /**< ASN1 length, e.g. in octets. */ + unsigned char *p; /**< ASN1 data, e.g. in ASCII. */ +} +asn1_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef struct _asn1_bitstring +{ + size_t len; /**< ASN1 length, e.g. in octets. */ + unsigned char unused_bits; /**< Number of unused bits at the end of the string */ + unsigned char *p; /**< Raw ASN1 data for the bit string */ +} +asn1_bitstring; + +/** + * Container for a sequence of ASN.1 items + */ +typedef struct _asn1_sequence +{ + asn1_buf buf; /**< Buffer containing the given ASN.1 item. */ + struct _asn1_sequence *next; /**< The next entry in the sequence. */ +} +asn1_sequence; + +/** + * Get the length of an ASN.1 element. + * Updates the pointer to immediately behind the length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the value + * + * \return 0 if successful, POLARSSL_ERR_ASN1_OUT_OF_DATA on reaching + * end of data, POLARSSL_ERR_ASN1_INVALID_LENGTH if length is + * unparseable. + */ +int asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ); + +/** + * Get the tag and length of the tag. Check for the requested tag. + * Updates the pointer to immediately behind the tag and length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the length + * \param tag The expected tag + * + * \return 0 if successful, POLARSSL_ERR_ASN1_UNEXPECTED_TAG if tag did + * not match requested tag, or another specific ASN.1 error code. + */ +int asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ); + +/** + * Retrieve a boolean ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int asn1_get_bool( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * Retrieve an integer ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int asn1_get_int( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * Retrieve a bitstring ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param bs The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int asn1_get_bitstring( unsigned char **p, const unsigned char *end, + asn1_bitstring *bs); + +/** + * Parses and splits an ASN.1 "SEQUENCE OF " + * Updated the pointer to immediately behind the full sequence tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param cur First variable in the chain to fill + * \param tag Type of sequence + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int asn1_get_sequence_of( unsigned char **p, + const unsigned char *end, + asn1_sequence *cur, + int tag); + +#if defined(POLARSSL_BIGNUM_C) +/** + * Retrieve a MPI value from an integer ASN.1 tag. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param X The MPI that will receive the value + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mpi *X ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* asn1.h */ diff --git a/src/libpolarssl/asn1parse.c b/src/libpolarssl/asn1parse.c new file mode 100644 index 0000000..5df0b45 --- /dev/null +++ b/src/libpolarssl/asn1parse.c @@ -0,0 +1,260 @@ +/* + * Generic ASN.1 parsing + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_ASN1_PARSE_C) + +#include "asn1.h" + +#if defined(POLARSSL_BIGNUM_C) +#include "bignum.h" +#endif + +#include +#include +#include + +/* + * ASN.1 DER decoding routines + */ +int asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ) +{ + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + if( ( **p & 0x80 ) == 0 ) + *len = *(*p)++; + else + { + switch( **p & 0x7F ) + { + case 1: + if( ( end - *p ) < 2 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + *len = (*p)[1]; + (*p) += 2; + break; + + case 2: + if( ( end - *p ) < 3 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (*p)[1] << 8 ) | (*p)[2]; + (*p) += 3; + break; + + case 3: + if( ( end - *p ) < 4 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (*p)[1] << 16 ) | ( (*p)[2] << 8 ) | (*p)[3]; + (*p) += 4; + break; + + case 4: + if( ( end - *p ) < 5 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (*p)[1] << 24 ) | ( (*p)[2] << 16 ) | ( (*p)[3] << 8 ) | (*p)[4]; + (*p) += 5; + break; + + default: + return( POLARSSL_ERR_ASN1_INVALID_LENGTH ); + } + } + + if( *len > (size_t) ( end - *p ) ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + return( 0 ); +} + +int asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ) +{ + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + if( **p != tag ) + return( POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); + + (*p)++; + + return( asn1_get_len( p, end, len ) ); +} + +int asn1_get_bool( unsigned char **p, + const unsigned char *end, + int *val ) +{ + int ret; + size_t len; + + if( ( ret = asn1_get_tag( p, end, &len, ASN1_BOOLEAN ) ) != 0 ) + return( ret ); + + if( len != 1 ) + return( POLARSSL_ERR_ASN1_INVALID_LENGTH ); + + *val = ( **p != 0 ) ? 1 : 0; + (*p)++; + + return( 0 ); +} + +int asn1_get_int( unsigned char **p, + const unsigned char *end, + int *val ) +{ + int ret; + size_t len; + + if( ( ret = asn1_get_tag( p, end, &len, ASN1_INTEGER ) ) != 0 ) + return( ret ); + + if( len > sizeof( int ) || ( **p & 0x80 ) != 0 ) + return( POLARSSL_ERR_ASN1_INVALID_LENGTH ); + + *val = 0; + + while( len-- > 0 ) + { + *val = ( *val << 8 ) | **p; + (*p)++; + } + + return( 0 ); +} + +#if defined(POLARSSL_BIGNUM_C) +int asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mpi *X ) +{ + int ret; + size_t len; + + if( ( ret = asn1_get_tag( p, end, &len, ASN1_INTEGER ) ) != 0 ) + return( ret ); + + ret = mpi_read_binary( X, *p, len ); + + *p += len; + + return( ret ); +} +#endif /* POLARSSL_BIGNUM_C */ + +int asn1_get_bitstring( unsigned char **p, const unsigned char *end, + asn1_bitstring *bs) +{ + int ret; + + /* Certificate type is a single byte bitstring */ + if( ( ret = asn1_get_tag( p, end, &bs->len, ASN1_BIT_STRING ) ) != 0 ) + return( ret ); + + /* Check length, subtract one for actual bit string length */ + if ( bs->len < 1 ) + return( POLARSSL_ERR_ASN1_OUT_OF_DATA ); + bs->len -= 1; + + /* Get number of unused bits, ensure unused bits <= 7 */ + bs->unused_bits = **p; + if( bs->unused_bits > 7 ) + return( POLARSSL_ERR_ASN1_INVALID_LENGTH ); + (*p)++; + + /* Get actual bitstring */ + bs->p = *p; + *p += bs->len; + + if( *p != end ) + return( POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return 0; +} + + +/* + * Parses and splits an ASN.1 "SEQUENCE OF " + */ +int asn1_get_sequence_of( unsigned char **p, + const unsigned char *end, + asn1_sequence *cur, + int tag) +{ + int ret; + size_t len; + asn1_buf *buf; + + /* Get main sequence tag */ + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + if( *p + len != end ) + return( POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + buf = &(cur->buf); + buf->tag = **p; + + if( ( ret = asn1_get_tag( p, end, &buf->len, tag ) ) != 0 ) + return( ret ); + + buf->p = *p; + *p += buf->len; + + /* Allocate and assign next pointer */ + if (*p < end) + { + cur->next = (asn1_sequence *) malloc( + sizeof( asn1_sequence ) ); + + if( cur->next == NULL ) + return( POLARSSL_ERR_ASN1_MALLOC_FAILED ); + + cur = cur->next; + } + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if( *p != end ) + return( POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +#endif diff --git a/src/libpolarssl/asn1write.c b/src/libpolarssl/asn1write.c new file mode 100644 index 0000000..059a5f5 --- /dev/null +++ b/src/libpolarssl/asn1write.c @@ -0,0 +1,241 @@ +/* + * ASN.1 buffer writing functionality + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_ASN1_WRITE_C) + +#include "asn1write.h" + +int asn1_write_len( unsigned char **p, unsigned char *start, size_t len ) +{ + if( len < 0x80 ) + { + if( *p - start < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = len; + return( 1 ); + } + + if( len <= 0xFF ) + { + if( *p - start < 2 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = len; + *--(*p) = 0x81; + return( 2 ); + } + + if( *p - start < 3 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + // We assume we never have lengths larger than 65535 bytes + // + *--(*p) = len % 256; + *--(*p) = ( len / 256 ) % 256; + *--(*p) = 0x82; + + return( 3 ); +} + +int asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag ) +{ + if( *p - start < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = tag; + + return( 1 ); +} + +int asn1_write_mpi( unsigned char **p, unsigned char *start, mpi *X ) +{ + int ret; + size_t len = 0; + + // Write the MPI + // + len = mpi_size( X ); + + if( *p - start < (int) len ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + (*p) -= len; + mpi_write_binary( X, *p, len ); + + // DER format assumes 2s complement for numbers, so the leftmost bit + // should be 0 for positive numbers and 1 for negative numbers. + // + if ( X->s ==1 && **p & 0x80 ) + { + if( *p - start < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_INTEGER ) ); + + return( len ); +} + +int asn1_write_null( unsigned char **p, unsigned char *start ) +{ + int ret; + size_t len = 0; + + // Write NULL + // + ASN1_CHK_ADD( len, asn1_write_len( p, start, 0) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_NULL ) ); + + return( len ); +} + +int asn1_write_oid( unsigned char **p, unsigned char *start, char *oid ) +{ + int ret; + size_t len = 0; + + // Write OID + // + len = strlen( oid ); + + if( *p - start < (int) len ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + (*p) -= len; + memcpy( *p, oid, len ); + + ASN1_CHK_ADD( len , asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len , asn1_write_tag( p, start, ASN1_OID ) ); + + return( len ); +} + +int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, + char *algorithm_oid ) +{ + int ret; + size_t null_len = 0; + size_t oid_len = 0; + size_t len = 0; + + // Write NULL + // + ASN1_CHK_ADD( null_len, asn1_write_null( p, start ) ); + + // Write OID + // + ASN1_CHK_ADD( oid_len, asn1_write_oid( p, start, algorithm_oid ) ); + + len = oid_len + null_len; + ASN1_CHK_ADD( len, asn1_write_len( p, start, oid_len + null_len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + return( len ); +} + +int asn1_write_int( unsigned char **p, unsigned char *start, int val ) +{ + int ret; + size_t len = 0; + + // TODO negative values and values larger than 128 + // DER format assumes 2s complement for numbers, so the leftmost bit + // should be 0 for positive numbers and 1 for negative numbers. + // + if( *p - start < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + len += 1; + *--(*p) = val; + + if ( val > 0 && **p & 0x80 ) + { + if( *p - start < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_INTEGER ) ); + + return( len ); +} + +int asn1_write_printable_string( unsigned char **p, unsigned char *start, + char *text ) +{ + int ret; + size_t len = 0; + + // Write string + // + len = strlen( text ); + + if( *p - start < (int) len ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + (*p) -= len; + memcpy( *p, text, len ); + + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_PRINTABLE_STRING ) ); + + return( len ); +} + +int asn1_write_ia5_string( unsigned char **p, unsigned char *start, + char *text ) +{ + int ret; + size_t len = 0; + + // Write string + // + len = strlen( text ); + + if( *p - start < (int) len ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + (*p) -= len; + memcpy( *p, text, len ); + + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_IA5_STRING ) ); + + return( len ); +} + + +#endif diff --git a/src/libpolarssl/asn1write.h b/src/libpolarssl/asn1write.h new file mode 100644 index 0000000..52b9baa --- /dev/null +++ b/src/libpolarssl/asn1write.h @@ -0,0 +1,46 @@ +/** + * \file asn1write.h + * + * \brief ASN.1 buffer writing functionality + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ASN1_WRITE_H +#define POLARSSL_ASN1_WRITE_H + +#include "asn1.h" + +#define ASN1_CHK_ADD(g, f) if( ( ret = f ) < 0 ) return( ret ); else g += ret + +int asn1_write_len( unsigned char **p, unsigned char *start, size_t len ); +int asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag ); +int asn1_write_mpi( unsigned char **p, unsigned char *start, mpi *X ); +int asn1_write_null( unsigned char **p, unsigned char *start ); +int asn1_write_oid( unsigned char **p, unsigned char *start, char *oid ); +int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, char *algorithm_oid ); +int asn1_write_int( unsigned char **p, unsigned char *start, int val ); +int asn1_write_printable_string( unsigned char **p, unsigned char *start, + char *text ); +int asn1_write_ia5_string( unsigned char **p, unsigned char *start, + char *text ); + +#endif /* POLARSSL_ASN1_WRITE_H */ diff --git a/src/libpolarssl/base64.c b/src/libpolarssl/base64.c new file mode 100644 index 0000000..0f8b5b2 --- /dev/null +++ b/src/libpolarssl/base64.c @@ -0,0 +1,262 @@ +/* + * RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_BASE64_C) + +#include "base64.h" + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +static const unsigned char base64_enc_map[64] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' +}; + +static const unsigned char base64_dec_map[128] = +{ + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, + 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 127, 127, 127, 127, 127 +}; + +/* + * Encode a buffer into base64 format + */ +int base64_encode( unsigned char *dst, size_t *dlen, + const unsigned char *src, size_t slen ) +{ + size_t i, n; + int C1, C2, C3; + unsigned char *p; + + if( slen == 0 ) + return( 0 ); + + n = (slen << 3) / 6; + + switch( (slen << 3) - (n * 6) ) + { + case 2: n += 3; break; + case 4: n += 2; break; + default: break; + } + + if( *dlen < n + 1 ) + { + *dlen = n + 1; + return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + n = (slen / 3) * 3; + + for( i = 0, p = dst; i < n; i += 3 ) + { + C1 = *src++; + C2 = *src++; + C3 = *src++; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F]; + *p++ = base64_enc_map[C3 & 0x3F]; + } + + if( i < slen ) + { + C1 = *src++; + C2 = ((i + 1) < slen) ? *src++ : 0; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + + if( (i + 1) < slen ) + *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F]; + else *p++ = '='; + + *p++ = '='; + } + + *dlen = p - dst; + *p = 0; + + return( 0 ); +} + +/* + * Decode a base64-formatted buffer + */ +int base64_decode( unsigned char *dst, size_t *dlen, + const unsigned char *src, size_t slen ) +{ + size_t i, n; + uint32_t j, x; + unsigned char *p; + + for( i = j = n = 0; i < slen; i++ ) + { + if( ( slen - i ) >= 2 && + src[i] == '\r' && src[i + 1] == '\n' ) + continue; + + if( src[i] == '\n' ) + continue; + + if( src[i] == '=' && ++j > 2 ) + return( POLARSSL_ERR_BASE64_INVALID_CHARACTER ); + + if( src[i] > 127 || base64_dec_map[src[i]] == 127 ) + return( POLARSSL_ERR_BASE64_INVALID_CHARACTER ); + + if( base64_dec_map[src[i]] < 64 && j != 0 ) + return( POLARSSL_ERR_BASE64_INVALID_CHARACTER ); + + n++; + } + + if( n == 0 ) + return( 0 ); + + n = ((n * 6) + 7) >> 3; + + if( *dlen < n ) + { + *dlen = n; + return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) + { + if( *src == '\r' || *src == '\n' ) + continue; + + j -= ( base64_dec_map[*src] == 64 ); + x = (x << 6) | ( base64_dec_map[*src] & 0x3F ); + + if( ++n == 4 ) + { + n = 0; + if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); + if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); + if( j > 2 ) *p++ = (unsigned char)( x ); + } + } + + *dlen = p - dst; + + return( 0 ); +} + +#if defined(POLARSSL_SELF_TEST) + +#include +#include + +static const unsigned char base64_test_dec[64] = +{ + 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD, + 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01, + 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09, + 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13, + 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31, + 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38, + 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B, + 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97 +}; + +static const unsigned char base64_test_enc[] = + "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK" + "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw=="; + +/* + * Checkup routine + */ +int base64_self_test( int verbose ) +{ + size_t len; + const unsigned char *src; + unsigned char buffer[128]; + + if( verbose != 0 ) + printf( " Base64 encoding test: " ); + + len = sizeof( buffer ); + src = base64_test_dec; + + if( base64_encode( buffer, &len, src, 64 ) != 0 || + memcmp( base64_test_enc, buffer, 88 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n Base64 decoding test: " ); + + len = sizeof( buffer ); + src = base64_test_enc; + + if( base64_decode( buffer, &len, src, 88 ) != 0 || + memcmp( base64_test_dec, buffer, 64 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/base64.h b/src/libpolarssl/base64.h new file mode 100644 index 0000000..fb0d753 --- /dev/null +++ b/src/libpolarssl/base64.h @@ -0,0 +1,87 @@ +/** + * \file base64.h + * + * \brief RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_BASE64_H +#define POLARSSL_BASE64_H + +#include + +#define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */ +#define POLARSSL_ERR_BASE64_INVALID_CHARACTER -0x002C /**< Invalid character in input. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encode a buffer into base64 format + * + * \param dst destination buffer + * \param dlen size of the buffer + * \param src source buffer + * \param slen amount of data to be encoded + * + * \return 0 if successful, or POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL. + * *dlen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dlen = 0 to obtain the + * required buffer size in *dlen + */ +int base64_encode( unsigned char *dst, size_t *dlen, + const unsigned char *src, size_t slen ); + +/** + * \brief Decode a base64-formatted buffer + * + * \param dst destination buffer + * \param dlen size of the buffer + * \param src source buffer + * \param slen amount of data to be decoded + * + * \return 0 if successful, POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL, or + * POLARSSL_ERR_BASE64_INVALID_CHARACTER if the input data is + * not correct. *dlen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dlen = 0 to obtain the + * required buffer size in *dlen + */ +int base64_decode( unsigned char *dst, size_t *dlen, + const unsigned char *src, size_t slen ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int base64_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* base64.h */ diff --git a/src/libpolarssl/bignum.c b/src/libpolarssl/bignum.c new file mode 100644 index 0000000..a0f10a0 --- /dev/null +++ b/src/libpolarssl/bignum.c @@ -0,0 +1,2143 @@ +/* + * Multi-precision integer library + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * This MPI implementation is based on: + * + * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf + * http://www.stillhq.com/extracted/gnupg-api/mpi/ + * http://math.libtomcrypt.com/files/tommath.pdf + */ + +#include "config.h" + +#if defined(POLARSSL_BIGNUM_C) + +#include "bignum.h" +#include "bn_mul.h" + +#include + +#define ciL (sizeof(t_uint)) /* chars in limb */ +#define biL (ciL << 3) /* bits in limb */ +#define biH (ciL << 2) /* half limb size */ + +/* + * Convert between bits/chars and number of limbs + */ +#define BITS_TO_LIMBS(i) (((i) + biL - 1) / biL) +#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL) + +/* + * Initialize one MPI + */ +void mpi_init( mpi *X ) +{ + if( X == NULL ) + return; + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Unallocate one MPI + */ +void mpi_free( mpi *X ) +{ + if( X == NULL ) + return; + + if( X->p != NULL ) + { + memset( X->p, 0, X->n * ciL ); + free( X->p ); + } + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Enlarge to the specified number of limbs + */ +int mpi_grow( mpi *X, size_t nblimbs ) +{ + t_uint *p; + + if( nblimbs > POLARSSL_MPI_MAX_LIMBS ) + return( POLARSSL_ERR_MPI_MALLOC_FAILED ); + + if( X->n < nblimbs ) + { + if( ( p = (t_uint *) malloc( nblimbs * ciL ) ) == NULL ) + return( POLARSSL_ERR_MPI_MALLOC_FAILED ); + + memset( p, 0, nblimbs * ciL ); + + if( X->p != NULL ) + { + memcpy( p, X->p, X->n * ciL ); + memset( X->p, 0, X->n * ciL ); + free( X->p ); + } + + X->n = nblimbs; + X->p = p; + } + + return( 0 ); +} + +/* + * Copy the contents of Y into X + */ +int mpi_copy( mpi *X, const mpi *Y ) +{ + int ret; + size_t i; + + if( X == Y ) + return( 0 ); + + for( i = Y->n - 1; i > 0; i-- ) + if( Y->p[i] != 0 ) + break; + i++; + + X->s = Y->s; + + MPI_CHK( mpi_grow( X, i ) ); + + memset( X->p, 0, X->n * ciL ); + memcpy( X->p, Y->p, i * ciL ); + +cleanup: + + return( ret ); +} + +/* + * Swap the contents of X and Y + */ +void mpi_swap( mpi *X, mpi *Y ) +{ + mpi T; + + memcpy( &T, X, sizeof( mpi ) ); + memcpy( X, Y, sizeof( mpi ) ); + memcpy( Y, &T, sizeof( mpi ) ); +} + +/* + * Set value from integer + */ +int mpi_lset( mpi *X, t_sint z ) +{ + int ret; + + MPI_CHK( mpi_grow( X, 1 ) ); + memset( X->p, 0, X->n * ciL ); + + X->p[0] = ( z < 0 ) ? -z : z; + X->s = ( z < 0 ) ? -1 : 1; + +cleanup: + + return( ret ); +} + +/* + * Get a specific bit + */ +int mpi_get_bit( const mpi *X, size_t pos ) +{ + if( X->n * biL <= pos ) + return( 0 ); + + return ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01; +} + +/* + * Set a bit to a specific value of 0 or 1 + */ +int mpi_set_bit( mpi *X, size_t pos, unsigned char val ) +{ + int ret = 0; + size_t off = pos / biL; + size_t idx = pos % biL; + + if( val != 0 && val != 1 ) + return POLARSSL_ERR_MPI_BAD_INPUT_DATA; + + if( X->n * biL <= pos ) + { + if( val == 0 ) + return ( 0 ); + + MPI_CHK( mpi_grow( X, off + 1 ) ); + } + + X->p[off] = ( X->p[off] & ~( 0x01 << idx ) ) | ( val << idx ); + +cleanup: + + return( ret ); +} + +/* + * Return the number of least significant bits + */ +size_t mpi_lsb( const mpi *X ) +{ + size_t i, j, count = 0; + + for( i = 0; i < X->n; i++ ) + for( j = 0; j < biL; j++, count++ ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + return( count ); + + return( 0 ); +} + +/* + * Return the number of most significant bits + */ +size_t mpi_msb( const mpi *X ) +{ + size_t i, j; + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + + for( j = biL; j > 0; j-- ) + if( ( ( X->p[i] >> ( j - 1 ) ) & 1 ) != 0 ) + break; + + return( ( i * biL ) + j ); +} + +/* + * Return the total size in bytes + */ +size_t mpi_size( const mpi *X ) +{ + return( ( mpi_msb( X ) + 7 ) >> 3 ); +} + +/* + * Convert an ASCII character to digit value + */ +static int mpi_get_digit( t_uint *d, int radix, char c ) +{ + *d = 255; + + if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; + if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; + if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; + + if( *d >= (t_uint) radix ) + return( POLARSSL_ERR_MPI_INVALID_CHARACTER ); + + return( 0 ); +} + +/* + * Import from an ASCII string + */ +int mpi_read_string( mpi *X, int radix, const char *s ) +{ + int ret; + size_t i, j, slen, n; + t_uint d; + mpi T; + + if( radix < 2 || radix > 16 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &T ); + + slen = strlen( s ); + + if( radix == 16 ) + { + n = BITS_TO_LIMBS( slen << 2 ); + + MPI_CHK( mpi_grow( X, n ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = slen, j = 0; i > 0; i--, j++ ) + { + if( i == 1 && s[i - 1] == '-' ) + { + X->s = -1; + break; + } + + MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) ); + X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 ); + } + } + else + { + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = 0; i < slen; i++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + continue; + } + + MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); + MPI_CHK( mpi_mul_int( &T, X, radix ) ); + + if( X->s == 1 ) + { + MPI_CHK( mpi_add_int( X, &T, d ) ); + } + else + { + MPI_CHK( mpi_sub_int( X, &T, d ) ); + } + } + } + +cleanup: + + mpi_free( &T ); + + return( ret ); +} + +/* + * Helper to write the digits high-order first + */ +static int mpi_write_hlp( mpi *X, int radix, char **p ) +{ + int ret; + t_uint r; + + if( radix < 2 || radix > 16 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + MPI_CHK( mpi_mod_int( &r, X, radix ) ); + MPI_CHK( mpi_div_int( X, NULL, X, radix ) ); + + if( mpi_cmp_int( X, 0 ) != 0 ) + MPI_CHK( mpi_write_hlp( X, radix, p ) ); + + if( r < 10 ) + *(*p)++ = (char)( r + 0x30 ); + else + *(*p)++ = (char)( r + 0x37 ); + +cleanup: + + return( ret ); +} + +/* + * Export into an ASCII string + */ +int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen ) +{ + int ret = 0; + size_t n; + char *p; + mpi T; + + if( radix < 2 || radix > 16 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + n = mpi_msb( X ); + if( radix >= 4 ) n >>= 1; + if( radix >= 16 ) n >>= 1; + n += 3; + + if( *slen < n ) + { + *slen = n; + return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); + } + + p = s; + mpi_init( &T ); + + if( X->s == -1 ) + *p++ = '-'; + + if( radix == 16 ) + { + int c; + size_t i, j, k; + + for( i = X->n, k = 0; i > 0; i-- ) + { + for( j = ciL; j > 0; j-- ) + { + c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF; + + if( c == 0 && k == 0 && ( i + j + 3 ) != 0 ) + continue; + + *(p++) = "0123456789ABCDEF" [c / 16]; + *(p++) = "0123456789ABCDEF" [c % 16]; + k = 1; + } + } + } + else + { + MPI_CHK( mpi_copy( &T, X ) ); + + if( T.s == -1 ) + T.s = 1; + + MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); + } + + *p++ = '\0'; + *slen = p - s; + +cleanup: + + mpi_free( &T ); + + return( ret ); +} + +#if defined(POLARSSL_FS_IO) +/* + * Read X from an opened file + */ +int mpi_read_file( mpi *X, int radix, FILE *fin ) +{ + t_uint d; + size_t slen; + char *p; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ POLARSSL_MPI_RW_BUFFER_SIZE ]; + + memset( s, 0, sizeof( s ) ); + if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) + return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); + + slen = strlen( s ); + if( slen == sizeof( s ) - 2 ) + return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); + + if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } + if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } + + p = s + slen; + while( --p >= s ) + if( mpi_get_digit( &d, radix, *p ) != 0 ) + break; + + return( mpi_read_string( X, radix, p + 1 ) ); +} + +/* + * Write X into an opened file (or stdout if fout == NULL) + */ +int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ) +{ + int ret; + size_t n, slen, plen; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ POLARSSL_MPI_RW_BUFFER_SIZE ]; + + n = sizeof( s ); + memset( s, 0, n ); + n -= 2; + + MPI_CHK( mpi_write_string( X, radix, s, (size_t *) &n ) ); + + if( p == NULL ) p = ""; + + plen = strlen( p ); + slen = strlen( s ); + s[slen++] = '\r'; + s[slen++] = '\n'; + + if( fout != NULL ) + { + if( fwrite( p, 1, plen, fout ) != plen || + fwrite( s, 1, slen, fout ) != slen ) + return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); + } + else + printf( "%s%s", p, s ); + +cleanup: + + return( ret ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * Import X from unsigned binary data, big endian + */ +int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t i, j, n; + + for( n = 0; n < buflen; n++ ) + if( buf[n] != 0 ) + break; + + MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i = buflen, j = 0; i > n; i--, j++ ) + X->p[j / ciL] |= ((t_uint) buf[i - 1]) << ((j % ciL) << 3); + +cleanup: + + return( ret ); +} + +/* + * Export X into unsigned binary data, big endian + */ +int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ) +{ + size_t i, j, n; + + n = mpi_size( X ); + + if( buflen < n ) + return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); + + memset( buf, 0, buflen ); + + for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) + buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); + + return( 0 ); +} + +/* + * Left-shift: X <<= count + */ +int mpi_shift_l( mpi *X, size_t count ) +{ + int ret; + size_t i, v0, t1; + t_uint r0 = 0, r1; + + v0 = count / (biL ); + t1 = count & (biL - 1); + + i = mpi_msb( X ) + count; + + if( X->n * biL < i ) + MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) ); + + ret = 0; + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = X->n; i > v0; i-- ) + X->p[i - 1] = X->p[i - v0 - 1]; + + for( ; i > 0; i-- ) + X->p[i - 1] = 0; + } + + /* + * shift by count % limb_size + */ + if( t1 > 0 ) + { + for( i = v0; i < X->n; i++ ) + { + r1 = X->p[i] >> (biL - t1); + X->p[i] <<= t1; + X->p[i] |= r0; + r0 = r1; + } + } + +cleanup: + + return( ret ); +} + +/* + * Right-shift: X >>= count + */ +int mpi_shift_r( mpi *X, size_t count ) +{ + size_t i, v0, v1; + t_uint r0 = 0, r1; + + v0 = count / biL; + v1 = count & (biL - 1); + + if( v0 > X->n || ( v0 == X->n && v1 > 0 ) ) + return mpi_lset( X, 0 ); + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = 0; i < X->n - v0; i++ ) + X->p[i] = X->p[i + v0]; + + for( ; i < X->n; i++ ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( v1 > 0 ) + { + for( i = X->n; i > 0; i-- ) + { + r1 = X->p[i - 1] << (biL - v1); + X->p[i - 1] >>= v1; + X->p[i - 1] |= r0; + r0 = r1; + } + } + + return( 0 ); +} + +/* + * Compare unsigned values + */ +int mpi_cmp_abs( const mpi *X, const mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( 1 ); + if( j > i ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( 1 ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -1 ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_mpi( const mpi *X, const mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( X->s ); + if( j > i ) return( -Y->s ); + + if( X->s > 0 && Y->s < 0 ) return( 1 ); + if( Y->s > 0 && X->s < 0 ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( X->s ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_int( const mpi *X, t_sint z ) +{ + mpi Y; + t_uint p[1]; + + *p = ( z < 0 ) ? -z : z; + Y.s = ( z < 0 ) ? -1 : 1; + Y.n = 1; + Y.p = p; + + return( mpi_cmp_mpi( X, &Y ) ); +} + +/* + * Unsigned addition: X = |A| + |B| (HAC 14.7) + */ +int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, j; + t_uint *o, *p, c; + + if( X == B ) + { + const mpi *T = A; A = X; B = T; + } + + if( X != A ) + MPI_CHK( mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned additions. + */ + X->s = 1; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MPI_CHK( mpi_grow( X, j ) ); + + o = B->p; p = X->p; c = 0; + + for( i = 0; i < j; i++, o++, p++ ) + { + *p += c; c = ( *p < c ); + *p += *o; c += ( *p < *o ); + } + + while( c != 0 ) + { + if( i >= X->n ) + { + MPI_CHK( mpi_grow( X, i + 1 ) ); + p = X->p + i; + } + + *p += c; c = ( *p < c ); i++; p++; + } + +cleanup: + + return( ret ); +} + +/* + * Helper for mpi substraction + */ +static void mpi_sub_hlp( size_t n, t_uint *s, t_uint *d ) +{ + size_t i; + t_uint c, z; + + for( i = c = 0; i < n; i++, s++, d++ ) + { + z = ( *d < c ); *d -= c; + c = ( *d < *s ) + z; *d -= *s; + } + + while( c != 0 ) + { + z = ( *d < c ); *d -= c; + c = z; i++; d++; + } +} + +/* + * Unsigned substraction: X = |A| - |B| (HAC 14.9) + */ +int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ) +{ + mpi TB; + int ret; + size_t n; + + if( mpi_cmp_abs( A, B ) < 0 ) + return( POLARSSL_ERR_MPI_NEGATIVE_VALUE ); + + mpi_init( &TB ); + + if( X == B ) + { + MPI_CHK( mpi_copy( &TB, B ) ); + B = &TB; + } + + if( X != A ) + MPI_CHK( mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned substractions. + */ + X->s = 1; + + ret = 0; + + for( n = B->n; n > 0; n-- ) + if( B->p[n - 1] != 0 ) + break; + + mpi_sub_hlp( n, B->p, X->p ); + +cleanup: + + mpi_free( &TB ); + + return( ret ); +} + +/* + * Signed addition: X = A + B + */ +int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s < 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MPI_CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MPI_CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed substraction: X = A - B + */ +int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s > 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MPI_CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MPI_CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed addition: X = A + b + */ +int mpi_add_int( mpi *X, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_add_mpi( X, A, &_B ) ); +} + +/* + * Signed substraction: X = A - b + */ +int mpi_sub_int( mpi *X, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_sub_mpi( X, A, &_B ) ); +} + +/* + * Helper for mpi multiplication + */ +static +#if defined(__APPLE__) && defined(__arm__) +/* + * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn) + * appears to need this to prevent bad ARM code generation at -O3. + */ +__attribute__ ((noinline)) +#endif +void mpi_mul_hlp( size_t i, t_uint *s, t_uint *d, t_uint b ) +{ + t_uint c = 0, t = 0; + +#if defined(MULADDC_HUIT) + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_HUIT + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#else + for( ; i >= 16; i -= 16 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#endif + + t++; + + do { + *d += c; c = ( *d < c ); d++; + } + while( c != 0 ); +} + +/* + * Baseline multiplication: X = A * B (HAC 14.12) + */ +int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, j; + mpi TA, TB; + + mpi_init( &TA ); mpi_init( &TB ); + + if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; } + if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; } + + for( i = A->n; i > 0; i-- ) + if( A->p[i - 1] != 0 ) + break; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MPI_CHK( mpi_grow( X, i + j ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + for( i++; j > 0; j-- ) + mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] ); + + X->s = A->s * B->s; + +cleanup: + + mpi_free( &TB ); mpi_free( &TA ); + + return( ret ); +} + +/* + * Baseline multiplication: X = A * b + */ +int mpi_mul_int( mpi *X, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + _B.s = 1; + _B.n = 1; + _B.p = p; + p[0] = b; + + return( mpi_mul_mpi( X, A, &_B ) ); +} + +/* + * Division by mpi: A = Q * B + R (HAC 14.20) + */ +int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ) +{ + int ret; + size_t i, n, t, k; + mpi X, Y, Z, T1, T2; + + if( mpi_cmp_int( B, 0 ) == 0 ) + return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); + + mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z ); + mpi_init( &T1 ); mpi_init( &T2 ); + + if( mpi_cmp_abs( A, B ) < 0 ) + { + if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) ); + if( R != NULL ) MPI_CHK( mpi_copy( R, A ) ); + return( 0 ); + } + + MPI_CHK( mpi_copy( &X, A ) ); + MPI_CHK( mpi_copy( &Y, B ) ); + X.s = Y.s = 1; + + MPI_CHK( mpi_grow( &Z, A->n + 2 ) ); + MPI_CHK( mpi_lset( &Z, 0 ) ); + MPI_CHK( mpi_grow( &T1, 2 ) ); + MPI_CHK( mpi_grow( &T2, 3 ) ); + + k = mpi_msb( &Y ) % biL; + if( k < biL - 1 ) + { + k = biL - 1 - k; + MPI_CHK( mpi_shift_l( &X, k ) ); + MPI_CHK( mpi_shift_l( &Y, k ) ); + } + else k = 0; + + n = X.n - 1; + t = Y.n - 1; + MPI_CHK( mpi_shift_l( &Y, biL * (n - t) ) ); + + while( mpi_cmp_mpi( &X, &Y ) >= 0 ) + { + Z.p[n - t]++; + mpi_sub_mpi( &X, &X, &Y ); + } + mpi_shift_r( &Y, biL * (n - t) ); + + for( i = n; i > t ; i-- ) + { + if( X.p[i] >= Y.p[t] ) + Z.p[i - t - 1] = ~0; + else + { +#if defined(POLARSSL_HAVE_UDBL) + t_udbl r; + + r = (t_udbl) X.p[i] << biL; + r |= (t_udbl) X.p[i - 1]; + r /= Y.p[t]; + if( r > ((t_udbl) 1 << biL) - 1) + r = ((t_udbl) 1 << biL) - 1; + + Z.p[i - t - 1] = (t_uint) r; +#else + /* + * __udiv_qrnnd_c, from gmp/longlong.h + */ + t_uint q0, q1, r0, r1; + t_uint d0, d1, d, m; + + d = Y.p[t]; + d0 = ( d << biH ) >> biH; + d1 = ( d >> biH ); + + q1 = X.p[i] / d1; + r1 = X.p[i] - d1 * q1; + r1 <<= biH; + r1 |= ( X.p[i - 1] >> biH ); + + m = q1 * d0; + if( r1 < m ) + { + q1--, r1 += d; + while( r1 >= d && r1 < m ) + q1--, r1 += d; + } + r1 -= m; + + q0 = r1 / d1; + r0 = r1 - d1 * q0; + r0 <<= biH; + r0 |= ( X.p[i - 1] << biH ) >> biH; + + m = q0 * d0; + if( r0 < m ) + { + q0--, r0 += d; + while( r0 >= d && r0 < m ) + q0--, r0 += d; + } + r0 -= m; + + Z.p[i - t - 1] = ( q1 << biH ) | q0; +#endif + } + + Z.p[i - t - 1]++; + do + { + Z.p[i - t - 1]--; + + MPI_CHK( mpi_lset( &T1, 0 ) ); + T1.p[0] = (t < 1) ? 0 : Y.p[t - 1]; + T1.p[1] = Y.p[t]; + MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); + + MPI_CHK( mpi_lset( &T2, 0 ) ); + T2.p[0] = (i < 2) ? 0 : X.p[i - 2]; + T2.p[1] = (i < 1) ? 0 : X.p[i - 1]; + T2.p[2] = X.p[i]; + } + while( mpi_cmp_mpi( &T1, &T2 ) > 0 ); + + MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); + MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); + MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); + + if( mpi_cmp_int( &X, 0 ) < 0 ) + { + MPI_CHK( mpi_copy( &T1, &Y ) ); + MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); + MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) ); + Z.p[i - t - 1]--; + } + } + + if( Q != NULL ) + { + mpi_copy( Q, &Z ); + Q->s = A->s * B->s; + } + + if( R != NULL ) + { + mpi_shift_r( &X, k ); + X.s = A->s; + mpi_copy( R, &X ); + + if( mpi_cmp_int( R, 0 ) == 0 ) + R->s = 1; + } + +cleanup: + + mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z ); + mpi_free( &T1 ); mpi_free( &T2 ); + + return( ret ); +} + +/* + * Division by int: A = Q * b + R + */ +int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b ) +{ + mpi _B; + t_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_div_mpi( Q, R, A, &_B ) ); +} + +/* + * Modulo: R = A mod B + */ +int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ) +{ + int ret; + + if( mpi_cmp_int( B, 0 ) < 0 ) + return POLARSSL_ERR_MPI_NEGATIVE_VALUE; + + MPI_CHK( mpi_div_mpi( NULL, R, A, B ) ); + + while( mpi_cmp_int( R, 0 ) < 0 ) + MPI_CHK( mpi_add_mpi( R, R, B ) ); + + while( mpi_cmp_mpi( R, B ) >= 0 ) + MPI_CHK( mpi_sub_mpi( R, R, B ) ); + +cleanup: + + return( ret ); +} + +/* + * Modulo: r = A mod b + */ +int mpi_mod_int( t_uint *r, const mpi *A, t_sint b ) +{ + size_t i; + t_uint x, y, z; + + if( b == 0 ) + return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); + + if( b < 0 ) + return POLARSSL_ERR_MPI_NEGATIVE_VALUE; + + /* + * handle trivial cases + */ + if( b == 1 ) + { + *r = 0; + return( 0 ); + } + + if( b == 2 ) + { + *r = A->p[0] & 1; + return( 0 ); + } + + /* + * general case + */ + for( i = A->n, y = 0; i > 0; i-- ) + { + x = A->p[i - 1]; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + + x <<= biH; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + } + + /* + * If A is negative, then the current y represents a negative value. + * Flipping it to the positive side. + */ + if( A->s < 0 && y != 0 ) + y = b - y; + + *r = y; + + return( 0 ); +} + +/* + * Fast Montgomery initialization (thanks to Tom St Denis) + */ +static void mpi_montg_init( t_uint *mm, const mpi *N ) +{ + t_uint x, m0 = N->p[0]; + + x = m0; + x += ( ( m0 + 2 ) & 4 ) << 1; + x *= ( 2 - ( m0 * x ) ); + + if( biL >= 16 ) x *= ( 2 - ( m0 * x ) ); + if( biL >= 32 ) x *= ( 2 - ( m0 * x ) ); + if( biL >= 64 ) x *= ( 2 - ( m0 * x ) ); + + *mm = ~x + 1; +} + +/* + * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) + */ +static void mpi_montmul( mpi *A, const mpi *B, const mpi *N, t_uint mm, const mpi *T ) +{ + size_t i, n, m; + t_uint u0, u1, *d; + + memset( T->p, 0, T->n * ciL ); + + d = T->p; + n = N->n; + m = ( B->n < n ) ? B->n : n; + + for( i = 0; i < n; i++ ) + { + /* + * T = (T + u0*B + u1*N) / 2^biL + */ + u0 = A->p[i]; + u1 = ( d[0] + u0 * B->p[0] ) * mm; + + mpi_mul_hlp( m, B->p, d, u0 ); + mpi_mul_hlp( n, N->p, d, u1 ); + + *d++ = u0; d[n + 1] = 0; + } + + memcpy( A->p, d, (n + 1) * ciL ); + + if( mpi_cmp_abs( A, N ) >= 0 ) + mpi_sub_hlp( n, N->p, A->p ); + else + /* prevent timing attacks */ + mpi_sub_hlp( n, A->p, T->p ); +} + +/* + * Montgomery reduction: A = A * R^-1 mod N + */ +static void mpi_montred( mpi *A, const mpi *N, t_uint mm, const mpi *T ) +{ + t_uint z = 1; + mpi U; + + U.n = U.s = (int) z; + U.p = &z; + + mpi_montmul( A, &U, N, mm, T ); +} + +/* + * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) + */ +int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ) +{ + int ret; + size_t wbits, wsize, one = 1; + size_t i, j, nblimbs; + size_t bufsize, nbits; + t_uint ei, mm, state; + mpi RR, T, W[ 2 << POLARSSL_MPI_WINDOW_SIZE ], Apos; + int neg; + + if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + if( mpi_cmp_int( E, 0 ) < 0 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + /* + * Init temps and window size + */ + mpi_montg_init( &mm, N ); + mpi_init( &RR ); mpi_init( &T ); + memset( W, 0, sizeof( W ) ); + + i = mpi_msb( E ); + + wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : + ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; + + if( wsize > POLARSSL_MPI_WINDOW_SIZE ) + wsize = POLARSSL_MPI_WINDOW_SIZE; + + j = N->n + 1; + MPI_CHK( mpi_grow( X, j ) ); + MPI_CHK( mpi_grow( &W[1], j ) ); + MPI_CHK( mpi_grow( &T, j * 2 ) ); + + /* + * Compensate for negative A (and correct at the end) + */ + neg = ( A->s == -1 ); + + mpi_init( &Apos ); + if( neg ) + { + MPI_CHK( mpi_copy( &Apos, A ) ); + Apos.s = 1; + A = &Apos; + } + + /* + * If 1st call, pre-compute R^2 mod N + */ + if( _RR == NULL || _RR->p == NULL ) + { + MPI_CHK( mpi_lset( &RR, 1 ) ); + MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) ); + MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) ); + + if( _RR != NULL ) + memcpy( _RR, &RR, sizeof( mpi ) ); + } + else + memcpy( &RR, _RR, sizeof( mpi ) ); + + /* + * W[1] = A * R^2 * R^-1 mod N = A * R mod N + */ + if( mpi_cmp_mpi( A, N ) >= 0 ) + mpi_mod_mpi( &W[1], A, N ); + else mpi_copy( &W[1], A ); + + mpi_montmul( &W[1], &RR, N, mm, &T ); + + /* + * X = R^2 * R^-1 mod N = R mod N + */ + MPI_CHK( mpi_copy( X, &RR ) ); + mpi_montred( X, N, mm, &T ); + + if( wsize > 1 ) + { + /* + * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) + */ + j = one << (wsize - 1); + + MPI_CHK( mpi_grow( &W[j], N->n + 1 ) ); + MPI_CHK( mpi_copy( &W[j], &W[1] ) ); + + for( i = 0; i < wsize - 1; i++ ) + mpi_montmul( &W[j], &W[j], N, mm, &T ); + + /* + * W[i] = W[i - 1] * W[1] + */ + for( i = j + 1; i < (one << wsize); i++ ) + { + MPI_CHK( mpi_grow( &W[i], N->n + 1 ) ); + MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) ); + + mpi_montmul( &W[i], &W[1], N, mm, &T ); + } + } + + nblimbs = E->n; + bufsize = 0; + nbits = 0; + wbits = 0; + state = 0; + + while( 1 ) + { + if( bufsize == 0 ) + { + if( nblimbs-- == 0 ) + break; + + bufsize = sizeof( t_uint ) << 3; + } + + bufsize--; + + ei = (E->p[nblimbs] >> bufsize) & 1; + + /* + * skip leading 0s + */ + if( ei == 0 && state == 0 ) + continue; + + if( ei == 0 && state == 1 ) + { + /* + * out of window, square X + */ + mpi_montmul( X, X, N, mm, &T ); + continue; + } + + /* + * add ei to current window + */ + state = 2; + + nbits++; + wbits |= (ei << (wsize - nbits)); + + if( nbits == wsize ) + { + /* + * X = X^wsize R^-1 mod N + */ + for( i = 0; i < wsize; i++ ) + mpi_montmul( X, X, N, mm, &T ); + + /* + * X = X * W[wbits] R^-1 mod N + */ + mpi_montmul( X, &W[wbits], N, mm, &T ); + + state--; + nbits = 0; + wbits = 0; + } + } + + /* + * process the remaining bits + */ + for( i = 0; i < nbits; i++ ) + { + mpi_montmul( X, X, N, mm, &T ); + + wbits <<= 1; + + if( (wbits & (one << wsize)) != 0 ) + mpi_montmul( X, &W[1], N, mm, &T ); + } + + /* + * X = A^E * R * R^-1 mod N = A^E mod N + */ + mpi_montred( X, N, mm, &T ); + + if( neg ) + { + X->s = -1; + mpi_add_mpi( X, N, X ); + } + +cleanup: + + for( i = (one << (wsize - 1)); i < (one << wsize); i++ ) + mpi_free( &W[i] ); + + mpi_free( &W[1] ); mpi_free( &T ); mpi_free( &Apos ); + + if( _RR == NULL ) + mpi_free( &RR ); + + return( ret ); +} + +/* + * Greatest common divisor: G = gcd(A, B) (HAC 14.54) + */ +int mpi_gcd( mpi *G, const mpi *A, const mpi *B ) +{ + int ret; + size_t lz, lzt; + mpi TG, TA, TB; + + mpi_init( &TG ); mpi_init( &TA ); mpi_init( &TB ); + + MPI_CHK( mpi_copy( &TA, A ) ); + MPI_CHK( mpi_copy( &TB, B ) ); + + lz = mpi_lsb( &TA ); + lzt = mpi_lsb( &TB ); + + if ( lzt < lz ) + lz = lzt; + + MPI_CHK( mpi_shift_r( &TA, lz ) ); + MPI_CHK( mpi_shift_r( &TB, lz ) ); + + TA.s = TB.s = 1; + + while( mpi_cmp_int( &TA, 0 ) != 0 ) + { + MPI_CHK( mpi_shift_r( &TA, mpi_lsb( &TA ) ) ); + MPI_CHK( mpi_shift_r( &TB, mpi_lsb( &TB ) ) ); + + if( mpi_cmp_mpi( &TA, &TB ) >= 0 ) + { + MPI_CHK( mpi_sub_abs( &TA, &TA, &TB ) ); + MPI_CHK( mpi_shift_r( &TA, 1 ) ); + } + else + { + MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) ); + MPI_CHK( mpi_shift_r( &TB, 1 ) ); + } + } + + MPI_CHK( mpi_shift_l( &TB, lz ) ); + MPI_CHK( mpi_copy( G, &TB ) ); + +cleanup: + + mpi_free( &TG ); mpi_free( &TA ); mpi_free( &TB ); + + return( ret ); +} + +int mpi_fill_random( mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + + MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( size ) ) ); + MPI_CHK( mpi_lset( X, 0 ) ); + + MPI_CHK( f_rng( p_rng, (unsigned char *) X->p, size ) ); + +cleanup: + return( ret ); +} + +/* + * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) + */ +int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ) +{ + int ret; + mpi G, TA, TU, U1, U2, TB, TV, V1, V2; + + if( mpi_cmp_int( N, 0 ) <= 0 ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &TA ); mpi_init( &TU ); mpi_init( &U1 ); mpi_init( &U2 ); + mpi_init( &G ); mpi_init( &TB ); mpi_init( &TV ); + mpi_init( &V1 ); mpi_init( &V2 ); + + MPI_CHK( mpi_gcd( &G, A, N ) ); + + if( mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + MPI_CHK( mpi_mod_mpi( &TA, A, N ) ); + MPI_CHK( mpi_copy( &TU, &TA ) ); + MPI_CHK( mpi_copy( &TB, N ) ); + MPI_CHK( mpi_copy( &TV, N ) ); + + MPI_CHK( mpi_lset( &U1, 1 ) ); + MPI_CHK( mpi_lset( &U2, 0 ) ); + MPI_CHK( mpi_lset( &V1, 0 ) ); + MPI_CHK( mpi_lset( &V2, 1 ) ); + + do + { + while( ( TU.p[0] & 1 ) == 0 ) + { + MPI_CHK( mpi_shift_r( &TU, 1 ) ); + + if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) + { + MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) ); + MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) ); + } + + MPI_CHK( mpi_shift_r( &U1, 1 ) ); + MPI_CHK( mpi_shift_r( &U2, 1 ) ); + } + + while( ( TV.p[0] & 1 ) == 0 ) + { + MPI_CHK( mpi_shift_r( &TV, 1 ) ); + + if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) + { + MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) ); + MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) ); + } + + MPI_CHK( mpi_shift_r( &V1, 1 ) ); + MPI_CHK( mpi_shift_r( &V2, 1 ) ); + } + + if( mpi_cmp_mpi( &TU, &TV ) >= 0 ) + { + MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) ); + MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) ); + MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) ); + } + else + { + MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) ); + MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) ); + MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) ); + } + } + while( mpi_cmp_int( &TU, 0 ) != 0 ); + + while( mpi_cmp_int( &V1, 0 ) < 0 ) + MPI_CHK( mpi_add_mpi( &V1, &V1, N ) ); + + while( mpi_cmp_mpi( &V1, N ) >= 0 ) + MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) ); + + MPI_CHK( mpi_copy( X, &V1 ) ); + +cleanup: + + mpi_free( &TA ); mpi_free( &TU ); mpi_free( &U1 ); mpi_free( &U2 ); + mpi_free( &G ); mpi_free( &TB ); mpi_free( &TV ); + mpi_free( &V1 ); mpi_free( &V2 ); + + return( ret ); +} + +#if defined(POLARSSL_GENPRIME) + +static const int small_prime[] = +{ + 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, + 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, + 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997, -103 +}; + +/* + * Miller-Rabin primality test (HAC 4.24) + */ +int mpi_is_prime( mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, xs; + size_t i, j, n, s; + mpi W, R, T, A, RR; + + if( mpi_cmp_int( X, 0 ) == 0 || + mpi_cmp_int( X, 1 ) == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + + if( mpi_cmp_int( X, 2 ) == 0 ) + return( 0 ); + + mpi_init( &W ); mpi_init( &R ); mpi_init( &T ); mpi_init( &A ); + mpi_init( &RR ); + + xs = X->s; X->s = 1; + + /* + * test trivial factors first + */ + if( ( X->p[0] & 1 ) == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + + for( i = 0; small_prime[i] > 0; i++ ) + { + t_uint r; + + if( mpi_cmp_int( X, small_prime[i] ) <= 0 ) + return( 0 ); + + MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) ); + + if( r == 0 ) + return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); + } + + /* + * W = |X| - 1 + * R = W >> lsb( W ) + */ + MPI_CHK( mpi_sub_int( &W, X, 1 ) ); + s = mpi_lsb( &W ); + MPI_CHK( mpi_copy( &R, &W ) ); + MPI_CHK( mpi_shift_r( &R, s ) ); + + i = mpi_msb( X ); + /* + * HAC, table 4.4 + */ + n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : + ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : + ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); + + for( i = 0; i < n; i++ ) + { + /* + * pick a random A, 1 < A < |X| - 1 + */ + MPI_CHK( mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + if( mpi_cmp_mpi( &A, &W ) >= 0 ) + { + j = mpi_msb( &A ) - mpi_msb( &W ); + MPI_CHK( mpi_shift_r( &A, j + 1 ) ); + } + A.p[0] |= 3; + + /* + * A = A^R mod |X| + */ + MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) ); + + if( mpi_cmp_mpi( &A, &W ) == 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + continue; + + j = 1; + while( j < s && mpi_cmp_mpi( &A, &W ) != 0 ) + { + /* + * A = A * A mod |X| + */ + MPI_CHK( mpi_mul_mpi( &T, &A, &A ) ); + MPI_CHK( mpi_mod_mpi( &A, &T, X ) ); + + if( mpi_cmp_int( &A, 1 ) == 0 ) + break; + + j++; + } + + /* + * not prime if A != |X| - 1 or A == 1 + */ + if( mpi_cmp_mpi( &A, &W ) != 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + { + ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; + break; + } + } + +cleanup: + + X->s = xs; + + mpi_free( &W ); mpi_free( &R ); mpi_free( &T ); mpi_free( &A ); + mpi_free( &RR ); + + return( ret ); +} + +/* + * Prime number generation + */ +int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t k, n; + mpi Y; + + if( nbits < 3 || nbits > POLARSSL_MPI_MAX_BITS ) + return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); + + mpi_init( &Y ); + + n = BITS_TO_LIMBS( nbits ); + + MPI_CHK( mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); + + k = mpi_msb( X ); + if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) ); + if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits ) ); + + X->p[0] |= 3; + + if( dh_flag == 0 ) + { + while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 ) + { + if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MPI_CHK( mpi_add_int( X, X, 2 ) ); + } + } + else + { + MPI_CHK( mpi_sub_int( &Y, X, 1 ) ); + MPI_CHK( mpi_shift_r( &Y, 1 ) ); + + while( 1 ) + { + if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 ) + { + if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 ) + break; + + if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + } + + if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MPI_CHK( mpi_add_int( &Y, X, 1 ) ); + MPI_CHK( mpi_add_int( X, X, 2 ) ); + MPI_CHK( mpi_shift_r( &Y, 1 ) ); + } + } + +cleanup: + + mpi_free( &Y ); + + return( ret ); +} + +#endif + +#if defined(POLARSSL_SELF_TEST) + +#define GCD_PAIR_COUNT 3 + +static const int gcd_pairs[GCD_PAIR_COUNT][3] = +{ + { 693, 609, 21 }, + { 1764, 868, 28 }, + { 768454923, 542167814, 1 } +}; + +/* + * Checkup routine + */ +int mpi_self_test( int verbose ) +{ + int ret, i; + mpi A, E, N, X, Y, U, V; + + mpi_init( &A ); mpi_init( &E ); mpi_init( &N ); mpi_init( &X ); + mpi_init( &Y ); mpi_init( &U ); mpi_init( &V ); + + MPI_CHK( mpi_read_string( &A, 16, + "EFE021C2645FD1DC586E69184AF4A31E" \ + "D5F53E93B5F123FA41680867BA110131" \ + "944FE7952E2517337780CB0DB80E61AA" \ + "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); + + MPI_CHK( mpi_read_string( &E, 16, + "B2E7EFD37075B9F03FF989C7C5051C20" \ + "34D2A323810251127E7BF8625A4F49A5" \ + "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ + "5B5C25763222FEFCCFC38B832366C29E" ) ); + + MPI_CHK( mpi_read_string( &N, 16, + "0066A198186C18C10B2F5ED9B522752A" \ + "9830B69916E535C8F047518A889A43A5" \ + "94B6BED27A168D31D4A52F88925AA8F5" ) ); + + MPI_CHK( mpi_mul_mpi( &X, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "602AB7ECA597A3D6B56FF9829A5E8B85" \ + "9E857EA95A03512E2BAE7391688D264A" \ + "A5663B0341DB9CCFD2C4C5F421FEC814" \ + "8001B72E848A38CAE1C65F78E56ABDEF" \ + "E12D3C039B8A02D6BE593F0BBBDA56F1" \ + "ECF677152EF804370C1A305CAF3B5BF1" \ + "30879B56C61DE584A0F53A2447A51E" ) ); + + if( verbose != 0 ) + printf( " MPI test #1 (mul_mpi): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "256567336059E52CAE22925474705F39A94" ) ); + + MPI_CHK( mpi_read_string( &V, 16, + "6613F26162223DF488E9CD48CC132C7A" \ + "0AC93C701B001B092E4E5B9F73BCD27B" \ + "9EE50D0657C77F374E903CDFA4C642" ) ); + + if( verbose != 0 ) + printf( " MPI test #2 (div_mpi): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 || + mpi_cmp_mpi( &Y, &V ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "36E139AEA55215609D2816998ED020BB" \ + "BD96C37890F65171D948E9BC7CBAA4D9" \ + "325D24D6A3C12710F10A09FA08AB87" ) ); + + if( verbose != 0 ) + printf( " MPI test #3 (exp_mod): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + +#if defined(POLARSSL_GENPRIME) + MPI_CHK( mpi_inv_mod( &X, &A, &N ) ); + + MPI_CHK( mpi_read_string( &U, 16, + "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ + "C3DBA76456363A10869622EAC2DD84EC" \ + "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); + + if( verbose != 0 ) + printf( " MPI test #4 (inv_mod): " ); + + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); +#endif + + if( verbose != 0 ) + printf( " MPI test #5 (simple gcd): " ); + + for ( i = 0; i < GCD_PAIR_COUNT; i++) + { + MPI_CHK( mpi_lset( &X, gcd_pairs[i][0] ) ); + MPI_CHK( mpi_lset( &Y, gcd_pairs[i][1] ) ); + + MPI_CHK( mpi_gcd( &A, &X, &Y ) ); + + if( mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 ) + { + if( verbose != 0 ) + printf( "failed at %d\n", i ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + +cleanup: + + if( ret != 0 && verbose != 0 ) + printf( "Unexpected error, return code = %08X\n", ret ); + + mpi_free( &A ); mpi_free( &E ); mpi_free( &N ); mpi_free( &X ); + mpi_free( &Y ); mpi_free( &U ); mpi_free( &V ); + + if( verbose != 0 ) + printf( "\n" ); + + return( ret ); +} + +#endif + +#endif diff --git a/src/libpolarssl/bignum.h b/src/libpolarssl/bignum.h new file mode 100644 index 0000000..afa9e61 --- /dev/null +++ b/src/libpolarssl/bignum.h @@ -0,0 +1,685 @@ +/** + * \file bignum.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_BIGNUM_H +#define POLARSSL_BIGNUM_H + +#include +#include + +#include "config.h" + +#ifdef _MSC_VER +#include +#if (_MSC_VER <= 1200) +typedef signed short int16_t; +typedef unsigned short uint16_t; +#else +typedef INT16 int16_t; +typedef UINT16 uint16_t; +#endif +typedef INT32 int32_t; +typedef INT64 int64_t; +typedef UINT32 uint32_t; +typedef UINT64 uint64_t; +#else +#include +#endif + +#define POLARSSL_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */ +#define POLARSSL_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */ +#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */ +#define POLARSSL_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */ +#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */ +#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ +#define POLARSSL_ERR_MPI_MALLOC_FAILED -0x0010 /**< Memory allocation failed. */ + +#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup + +/* + * Maximum size MPIs are allowed to grow to in number of limbs. + */ +#define POLARSSL_MPI_MAX_LIMBS 10000 + +#if !defined(POLARSSL_CONFIG_OPTIONS) +/* + * Maximum window size used for modular exponentiation. Default: 6 + * Minimum value: 1. Maximum value: 6. + * + * Result is an array of ( 2 << POLARSSL_MPI_WINDOW_SIZE ) MPIs used + * for the sliding window calculation. (So 64 by default) + * + * Reduction in size, reduces speed. + */ +#define POLARSSL_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ + +/* + * Maximum size of MPIs allowed in bits and bytes for user-MPIs. + * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits ) + * + * Note: Calculations can results temporarily in larger MPIs. So the number + * of limbs required (POLARSSL_MPI_MAX_LIMBS) is higher. + */ +#define POLARSSL_MPI_MAX_SIZE 512 /**< Maximum number of bytes for usable MPIs. */ + +#endif /* !POLARSSL_CONFIG_OPTIONS */ + +#define POLARSSL_MPI_MAX_BITS ( 8 * POLARSSL_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */ + +/* + * When reading from files with mpi_read_file() and writing to files with + * mpi_write_file() the buffer should have space + * for a (short) label, the MPI (in the provided radix), the newline + * characters and the '\0'. + * + * By default we assume at least a 10 char label, a minimum radix of 10 + * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars). + * Autosized at compile time for at least a 10 char label, a minimum radix + * of 10 (decimal) for a number of POLARSSL_MPI_MAX_BITS size. + * + * This used to be statically sized to 1250 for a maximum of 4096 bit + * numbers (1234 decimal chars). + * + * Calculate using the formula: + * POLARSSL_MPI_RW_BUFFER_SIZE = ceil(POLARSSL_MPI_MAX_BITS / ln(10) * ln(2)) + + * LabelSize + 6 + */ +#define POLARSSL_MPI_MAX_BITS_SCALE100 ( 100 * POLARSSL_MPI_MAX_BITS ) +#define LN_2_DIV_LN_10_SCALE100 332 +#define POLARSSL_MPI_RW_BUFFER_SIZE ( ((POLARSSL_MPI_MAX_BITS_SCALE100 + LN_2_DIV_LN_10_SCALE100 - 1) / LN_2_DIV_LN_10_SCALE100) + 10 + 6 ) + +/* + * Define the base integer type, architecture-wise + */ +#if defined(POLARSSL_HAVE_INT8) +typedef signed char t_sint; +typedef unsigned char t_uint; +typedef uint16_t t_udbl; +#define POLARSSL_HAVE_UDBL +#else +#if defined(POLARSSL_HAVE_INT16) +typedef int16_t t_sint; +typedef uint16_t t_uint; +typedef uint32_t t_udbl; +#define POLARSSL_HAVE_UDBL +#else + #if ( defined(_MSC_VER) && defined(_M_AMD64) ) + typedef int64_t t_sint; + typedef uint64_t t_uint; + #else + #if ( defined(__GNUC__) && ( \ + defined(__amd64__) || defined(__x86_64__) || \ + defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__ia64__) || defined(__alpha__) || \ + (defined(__sparc__) && defined(__arch64__)) || \ + defined(__s390x__) ) ) + typedef int64_t t_sint; + typedef uint64_t t_uint; + typedef unsigned int t_udbl __attribute__((mode(TI))); + #define POLARSSL_HAVE_UDBL + #else + typedef int32_t t_sint; + typedef uint32_t t_uint; + #if ( defined(_MSC_VER) && defined(_M_IX86) ) + typedef uint64_t t_udbl; + #define POLARSSL_HAVE_UDBL + #else + #if defined( POLARSSL_HAVE_LONGLONG ) + typedef unsigned long long t_udbl; + #define POLARSSL_HAVE_UDBL + #endif + #endif + #endif + #endif +#endif /* POLARSSL_HAVE_INT16 */ +#endif /* POLARSSL_HAVE_INT8 */ + +/** + * \brief MPI structure + */ +typedef struct +{ + int s; /*!< integer sign */ + size_t n; /*!< total # of limbs */ + t_uint *p; /*!< pointer to limbs */ +} +mpi; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize one MPI + * + * \param X One MPI to initialize. + */ +void mpi_init( mpi *X ); + +/** + * \brief Unallocate one MPI + * + * \param X One MPI to unallocate. + */ +void mpi_free( mpi *X ); + +/** + * \brief Enlarge to the specified number of limbs + * + * \param X MPI to grow + * \param nblimbs The target number of limbs + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_grow( mpi *X, size_t nblimbs ); + +/** + * \brief Copy the contents of Y into X + * + * \param X Destination MPI + * \param Y Source MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_copy( mpi *X, const mpi *Y ); + +/** + * \brief Swap the contents of X and Y + * + * \param X First MPI value + * \param Y Second MPI value + */ +void mpi_swap( mpi *X, mpi *Y ); + +/** + * \brief Set value from integer + * + * \param X MPI to set + * \param z Value to use + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_lset( mpi *X, t_sint z ); + +/** + * \brief Get a specific bit from X + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * + * \return Either a 0 or a 1 + */ +int mpi_get_bit( const mpi *X, size_t pos ); + +/** + * \brief Set a bit of X to a specific value of 0 or 1 + * + * \note Will grow X if necessary to set a bit to 1 in a not yet + * existing limb. Will not grow if bit should be set to 0 + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * \param val The value to set the bit to (0 or 1) + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1 + */ +int mpi_set_bit( mpi *X, size_t pos, unsigned char val ); + +/** + * \brief Return the number of zero-bits before the least significant + * '1' bit + * + * Note: Thus also the zero-based index of the least significant '1' bit + * + * \param X MPI to use + */ +size_t mpi_lsb( const mpi *X ); + +/** + * \brief Return the number of bits up to and including the most + * significant '1' bit' + * + * Note: Thus also the one-based index of the most significant '1' bit + * + * \param X MPI to use + */ +size_t mpi_msb( const mpi *X ); + +/** + * \brief Return the total size in bytes + * + * \param X MPI to use + */ +size_t mpi_size( const mpi *X ); + +/** + * \brief Import from an ASCII string + * + * \param X Destination MPI + * \param radix Input numeric base + * \param s Null-terminated string buffer + * + * \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code + */ +int mpi_read_string( mpi *X, int radix, const char *s ); + +/** + * \brief Export into an ASCII string + * + * \param X Source MPI + * \param radix Output numeric base + * \param s String buffer + * \param slen String buffer size + * + * \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code. + * *slen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *slen = 0 to obtain the + * minimum required buffer size in *slen. + */ +int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen ); + +#if defined(POLARSSL_FS_IO) +/** + * \brief Read X from an opened file + * + * \param X Destination MPI + * \param radix Input numeric base + * \param fin Input file handle + * + * \return 0 if successful, POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if + * the file read buffer is too small or a + * POLARSSL_ERR_MPI_XXX error code + */ +int mpi_read_file( mpi *X, int radix, FILE *fin ); + +/** + * \brief Write X into an opened file, or stdout if fout is NULL + * + * \param p Prefix, can be NULL + * \param X Source MPI + * \param radix Output numeric base + * \param fout Output file handle (can be NULL) + * + * \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code + * + * \note Set fout == NULL to print X on the console. + */ +int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ); +#endif /* POLARSSL_FS_IO */ + +/** + * \brief Import X from unsigned binary data, big endian + * + * \param X Destination MPI + * \param buf Input buffer + * \param buflen Input buffer size + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ); + +/** + * \brief Export X into unsigned binary data, big endian + * + * \param X Source MPI + * \param buf Output buffer + * \param buflen Output buffer size + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + */ +int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ); + +/** + * \brief Left-shift: X <<= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_shift_l( mpi *X, size_t count ); + +/** + * \brief Right-shift: X >>= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_shift_r( mpi *X, size_t count ); + +/** + * \brief Compare unsigned values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if |X| is greater than |Y|, + * -1 if |X| is lesser than |Y| or + * 0 if |X| is equal to |Y| + */ +int mpi_cmp_abs( const mpi *X, const mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if X is greater than Y, + * -1 if X is lesser than Y or + * 0 if X is equal to Y + */ +int mpi_cmp_mpi( const mpi *X, const mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param z The integer value to compare to + * + * \return 1 if X is greater than z, + * -1 if X is lesser than z or + * 0 if X is equal to z + */ +int mpi_cmp_int( const mpi *X, t_sint z ); + +/** + * \brief Unsigned addition: X = |A| + |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Unsigned substraction: X = |A| - |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A + */ +int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed addition: X = A + B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed substraction: X = A - B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Signed addition: X = A + b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to add + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_add_int( mpi *X, const mpi *A, t_sint b ); + +/** + * \brief Signed substraction: X = A - b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to subtract + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_sub_int( mpi *X, const mpi *A, t_sint b ); + +/** + * \brief Baseline multiplication: X = A * B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ); + +/** + * \brief Baseline multiplication: X = A * b + * Note: b is an unsigned integer type, thus + * Negative values of b are ignored. + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to multiply with + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_mul_int( mpi *X, const mpi *A, t_sint b ); + +/** + * \brief Division by mpi: A = Q * B + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ); + +/** + * \brief Division by int: A = Q * b + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b ); + +/** + * \brief Modulo: R = A mod B + * + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0, + * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B < 0 + */ +int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ); + +/** + * \brief Modulo: r = A mod b + * + * \param r Destination t_uint + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0, + * POLARSSL_ERR_MPI_NEGATIVE_VALUE if b < 0 + */ +int mpi_mod_int( t_uint *r, const mpi *A, t_sint b ); + +/** + * \brief Sliding-window exponentiation: X = A^E mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param E Exponent MPI + * \param N Modular MPI + * \param _RR Speed-up MPI used for recalculations + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even or if + * E is negative + * + * \note _RR is used to avoid re-computing R*R mod N across + * multiple calls, which speeds up things a bit. It can + * be set to NULL if the extra performance is unneeded. + */ +int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ); + +/** + * \brief Fill an MPI X with size bytes of random + * + * \param X Destination MPI + * \param size Size in bytes + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_fill_random( mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Greatest common divisor: G = gcd(A, B) + * + * \param G Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed + */ +int mpi_gcd( mpi *G, const mpi *A, const mpi *B ); + +/** + * \brief Modular inverse: X = A^-1 mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param N Right-hand MPI + * + * \return 0 if successful, + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil + POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N + */ +int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ); + +/** + * \brief Miller-Rabin primality test + * + * \param X MPI to check + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime + */ +int mpi_is_prime( mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Prime number generation + * + * \param X Destination MPI + * \param nbits Required size of X in bits ( 3 <= nbits <= POLARSSL_MPI_MAX_BITS ) + * \param dh_flag If 1, then (X-1)/2 will be prime too + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, + * POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 + */ +int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mpi_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* bignum.h */ diff --git a/src/libpolarssl/blowfish.c b/src/libpolarssl/blowfish.c new file mode 100644 index 0000000..e8ab667 --- /dev/null +++ b/src/libpolarssl/blowfish.c @@ -0,0 +1,632 @@ +/* + * Blowfish implementation + * + * Copyright (C) 2012-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The Blowfish block cipher was designed by Bruce Schneier in 1993. + * http://www.schneier.com/blowfish.html + * http://en.wikipedia.org/wiki/Blowfish_%28cipher%29 + * + */ + +#include "config.h" + +#if defined(POLARSSL_BLOWFISH_C) + +#include "blowfish.h" + +#if !defined(POLARSSL_BLOWFISH_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +static const uint32_t P[BLOWFISH_ROUNDS + 2] = { + 0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L, + 0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L, + 0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL, + 0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L, + 0x9216D5D9L, 0x8979FB1BL +}; + +/* declarations of data at the end of this file */ +static const uint32_t S[4][256]; + +static uint32_t F(blowfish_context *ctx, uint32_t x) +{ + unsigned short a, b, c, d; + uint32_t y; + + d = (unsigned short)(x & 0xFF); + x >>= 8; + c = (unsigned short)(x & 0xFF); + x >>= 8; + b = (unsigned short)(x & 0xFF); + x >>= 8; + a = (unsigned short)(x & 0xFF); + y = ctx->S[0][a] + ctx->S[1][b]; + y = y ^ ctx->S[2][c]; + y = y + ctx->S[3][d]; + + return y; +} + +static void blowfish_enc(blowfish_context *ctx, uint32_t *xl, uint32_t *xr) +{ + uint32_t Xl, Xr, temp; + short i; + + Xl = *xl; + Xr = *xr; + + for (i = 0; i < BLOWFISH_ROUNDS; ++i) + { + Xl = Xl ^ ctx->P[i]; + Xr = F(ctx, Xl) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx->P[BLOWFISH_ROUNDS]; + Xl = Xl ^ ctx->P[BLOWFISH_ROUNDS + 1]; + + *xl = Xl; + *xr = Xr; +} + +static void blowfish_dec(blowfish_context *ctx, uint32_t *xl, uint32_t *xr) +{ + uint32_t Xl, Xr, temp; + short i; + + Xl = *xl; + Xr = *xr; + + for (i = BLOWFISH_ROUNDS + 1; i > 1; --i) + { + Xl = Xl ^ ctx->P[i]; + Xr = F(ctx, Xl) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx->P[1]; + Xl = Xl ^ ctx->P[0]; + + *xl = Xl; + *xr = Xr; +} + +/* + * Blowfish key schedule + */ +int blowfish_setkey( blowfish_context *ctx, const unsigned char *key, unsigned int keysize ) +{ + unsigned int i, j, k; + uint32_t data, datal, datar; + + if( keysize < BLOWFISH_MIN_KEY || keysize > BLOWFISH_MAX_KEY || + ( keysize % 8 ) ) + { + return POLARSSL_ERR_BLOWFISH_INVALID_KEY_LENGTH; + } + + keysize >>= 3; + + for( i = 0; i < 4; i++ ) + { + for( j = 0; j < 256; j++ ) + ctx->S[i][j] = S[i][j]; + } + + j = 0; + for( i = 0; i < BLOWFISH_ROUNDS + 2; ++i ) + { + data = 0x00000000; + for( k = 0; k < 4; ++k ) + { + data = ( data << 8 ) | key[j++]; + if( j >= keysize ) + j = 0; + } + ctx->P[i] = P[i] ^ data; + } + + datal = 0x00000000; + datar = 0x00000000; + + for( i = 0; i < BLOWFISH_ROUNDS + 2; i += 2 ) + { + blowfish_enc( ctx, &datal, &datar ); + ctx->P[i] = datal; + ctx->P[i + 1] = datar; + } + + for( i = 0; i < 4; i++ ) + { + for( j = 0; j < 256; j += 2 ) + { + blowfish_enc( ctx, &datal, &datar ); + ctx->S[i][j] = datal; + ctx->S[i][j + 1] = datar; + } + } + return( 0 ); +} + +/* + * Blowfish-ECB block encryption/decryption + */ +int blowfish_crypt_ecb( blowfish_context *ctx, + int mode, + const unsigned char input[BLOWFISH_BLOCKSIZE], + unsigned char output[BLOWFISH_BLOCKSIZE] ) +{ + uint32_t X0, X1; + + GET_UINT32_BE( X0, input, 0 ); + GET_UINT32_BE( X1, input, 4 ); + + if( mode == BLOWFISH_DECRYPT ) + { + blowfish_dec(ctx, &X0, &X1); + } + else /* BLOWFISH_ENCRYPT */ + { + blowfish_enc(ctx, &X0, &X1); + } + + PUT_UINT32_BE( X0, output, 0 ); + PUT_UINT32_BE( X1, output, 4 ); + + return( 0 ); +} + +/* + * Blowfish-CBC buffer encryption/decryption + */ +int blowfish_crypt_cbc( blowfish_context *ctx, + int mode, + size_t length, + unsigned char iv[BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[BLOWFISH_BLOCKSIZE]; + + if( length % BLOWFISH_BLOCKSIZE ) + return( POLARSSL_ERR_BLOWFISH_INVALID_INPUT_LENGTH ); + + if( mode == BLOWFISH_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, BLOWFISH_BLOCKSIZE ); + blowfish_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < BLOWFISH_BLOCKSIZE;i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, BLOWFISH_BLOCKSIZE ); + + input += BLOWFISH_BLOCKSIZE; + output += BLOWFISH_BLOCKSIZE; + length -= BLOWFISH_BLOCKSIZE; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < BLOWFISH_BLOCKSIZE; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + blowfish_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, BLOWFISH_BLOCKSIZE ); + + input += BLOWFISH_BLOCKSIZE; + output += BLOWFISH_BLOCKSIZE; + length -= BLOWFISH_BLOCKSIZE; + } + } + + return( 0 ); +} + +#if defined(POLARSSL_CIPHER_MODE_CFB) +/* + * Blowfish CFB buffer encryption/decryption + */ +int blowfish_crypt_cfb64( blowfish_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == BLOWFISH_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + blowfish_crypt_ecb( ctx, BLOWFISH_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = (n + 1) % BLOWFISH_BLOCKSIZE; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + blowfish_crypt_ecb( ctx, BLOWFISH_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = (n + 1) % BLOWFISH_BLOCKSIZE; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /*POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +/* + * Blowfish CTR buffer encryption/decryption + */ +int blowfish_crypt_ctr( blowfish_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[BLOWFISH_BLOCKSIZE], + unsigned char stream_block[BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + blowfish_crypt_ecb( ctx, BLOWFISH_ENCRYPT, nonce_counter, stream_block ); + + for( i = BLOWFISH_BLOCKSIZE; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = (n + 1) % BLOWFISH_BLOCKSIZE; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* POLARSSL_CIPHER_MODE_CTR */ + +static const uint32_t S[4][256] = { + { 0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L, + 0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L, + 0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L, + 0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL, + 0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL, + 0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L, + 0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL, + 0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL, + 0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L, + 0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L, + 0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL, + 0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL, + 0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL, + 0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L, + 0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L, + 0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L, + 0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L, + 0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L, + 0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL, + 0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L, + 0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L, + 0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L, + 0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L, + 0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL, + 0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L, + 0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL, + 0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL, + 0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L, + 0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL, + 0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L, + 0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL, + 0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L, + 0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L, + 0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL, + 0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L, + 0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L, + 0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL, + 0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L, + 0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL, + 0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L, + 0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L, + 0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL, + 0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L, + 0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L, + 0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L, + 0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L, + 0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L, + 0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL, + 0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL, + 0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L, + 0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L, + 0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L, + 0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L, + 0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL, + 0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L, + 0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL, + 0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL, + 0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L, + 0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L, + 0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L, + 0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L, + 0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L, + 0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L, + 0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076AL }, + { 0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L, + 0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L, + 0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L, + 0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL, + 0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L, + 0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L, + 0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL, + 0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L, + 0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L, + 0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L, + 0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL, + 0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL, + 0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L, + 0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L, + 0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L, + 0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L, + 0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL, + 0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL, + 0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL, + 0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L, + 0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL, + 0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L, + 0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L, + 0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL, + 0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL, + 0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L, + 0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL, + 0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L, + 0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL, + 0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL, + 0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L, + 0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L, + 0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L, + 0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L, + 0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L, + 0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L, + 0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L, + 0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL, + 0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L, + 0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL, + 0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L, + 0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L, + 0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L, + 0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L, + 0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L, + 0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L, + 0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L, + 0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L, + 0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L, + 0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L, + 0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L, + 0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L, + 0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L, + 0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L, + 0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L, + 0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L, + 0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL, + 0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL, + 0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L, + 0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL, + 0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L, + 0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L, + 0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L, + 0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7L }, + { 0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L, + 0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L, + 0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL, + 0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L, + 0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L, + 0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L, + 0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL, + 0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL, + 0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL, + 0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L, + 0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L, + 0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL, + 0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L, + 0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL, + 0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L, + 0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL, + 0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L, + 0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL, + 0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L, + 0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL, + 0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L, + 0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L, + 0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL, + 0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L, + 0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L, + 0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L, + 0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L, + 0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL, + 0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L, + 0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL, + 0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L, + 0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL, + 0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L, + 0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL, + 0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL, + 0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL, + 0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L, + 0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L, + 0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL, + 0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL, + 0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL, + 0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL, + 0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL, + 0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L, + 0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L, + 0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L, + 0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L, + 0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL, + 0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL, + 0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L, + 0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L, + 0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L, + 0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L, + 0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L, + 0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L, + 0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L, + 0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L, + 0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L, + 0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L, + 0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL, + 0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L, + 0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL, + 0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L, + 0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0L }, + { 0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL, + 0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL, + 0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL, + 0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L, + 0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L, + 0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L, + 0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L, + 0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L, + 0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L, + 0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L, + 0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L, + 0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L, + 0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L, + 0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L, + 0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L, + 0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL, + 0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL, + 0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L, + 0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL, + 0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL, + 0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL, + 0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L, + 0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL, + 0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL, + 0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L, + 0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L, + 0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L, + 0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L, + 0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL, + 0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL, + 0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L, + 0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L, + 0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L, + 0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL, + 0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L, + 0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L, + 0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L, + 0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL, + 0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L, + 0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L, + 0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L, + 0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL, + 0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL, + 0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L, + 0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L, + 0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L, + 0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L, + 0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL, + 0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L, + 0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL, + 0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL, + 0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L, + 0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L, + 0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL, + 0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L, + 0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL, + 0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L, + 0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL, + 0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L, + 0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L, + 0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL, + 0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L, + 0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL, + 0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6L } +}; + +#endif /* !POLARSSL_BLOWFISH_ALT */ +#endif /* POLARSSL_BLOWFISH_C */ diff --git a/src/libpolarssl/blowfish.h b/src/libpolarssl/blowfish.h new file mode 100644 index 0000000..9b269b7 --- /dev/null +++ b/src/libpolarssl/blowfish.h @@ -0,0 +1,171 @@ +/** + * \file blowfish.h + * + * \brief Blowfish block cipher + * + * Copyright (C) 2012-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_BLOWFISH_H +#define POLARSSL_BLOWFISH_H + +#include "config.h" + +#include + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define BLOWFISH_ENCRYPT 1 +#define BLOWFISH_DECRYPT 0 +#define BLOWFISH_MAX_KEY 448 +#define BLOWFISH_MIN_KEY 32 +#define BLOWFISH_ROUNDS 16 /* when increasing this value, make sure to extend the initialisation vectors */ +#define BLOWFISH_BLOCKSIZE 8 /* Blowfish uses 64 bit blocks */ + +#define POLARSSL_ERR_BLOWFISH_INVALID_KEY_LENGTH -0x0016 /**< Invalid key length. */ +#define POLARSSL_ERR_BLOWFISH_INVALID_INPUT_LENGTH -0x0018 /**< Invalid data input length. */ + +#if !defined(POLARSSL_BLOWFISH_ALT) +// Regular implementation +// + +/** + * \brief Blowfish context structure + */ +typedef struct +{ + uint32_t P[BLOWFISH_ROUNDS + 2]; /*!< Blowfish round keys */ + uint32_t S[4][256]; /*!< key dependent S-boxes */ +} +blowfish_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Blowfish key schedule + * + * \param ctx Blowfish context to be initialized + * \param key encryption key + * \param keysize must be between 32 and 448 bits + * + * \return 0 if successful, or POLARSSL_ERR_BLOWFISH_INVALID_KEY_LENGTH + */ +int blowfish_setkey( blowfish_context *ctx, const unsigned char *key, unsigned int keysize ); + +/** + * \brief Blowfish-ECB block encryption/decryption + * + * \param ctx Blowfish context + * \param mode BLOWFISH_ENCRYPT or BLOWFISH_DECRYPT + * \param input 8-byte input block + * \param output 8-byte output block + * + * \return 0 if successful + */ +int blowfish_crypt_ecb( blowfish_context *ctx, + int mode, + const unsigned char input[BLOWFISH_BLOCKSIZE], + unsigned char output[BLOWFISH_BLOCKSIZE] ); + +/** + * \brief Blowfish-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (8 bytes) + * + * \param ctx Blowfish context + * \param mode BLOWFISH_ENCRYPT or BLOWFISH_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or POLARSSL_ERR_BLOWFISH_INVALID_INPUT_LENGTH + */ +int blowfish_crypt_cbc( blowfish_context *ctx, + int mode, + size_t length, + unsigned char iv[BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Blowfish CFB buffer encryption/decryption. + * + * both + * \param ctx Blowfish context + * \param mode BLOWFISH_ENCRYPT or BLOWFISH_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int blowfish_crypt_cfb64( blowfish_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Blowfish-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 64-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int blowfish_crypt_ctr( blowfish_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[BLOWFISH_BLOCKSIZE], + unsigned char stream_block[BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_BLOWFISH_ALT */ +#include "blowfish_alt.h" +#endif /* POLARSSL_BLOWFISH_ALT */ + +#endif /* blowfish.h */ diff --git a/src/libpolarssl/bn_mul.h b/src/libpolarssl/bn_mul.h new file mode 100644 index 0000000..1c2da13 --- /dev/null +++ b/src/libpolarssl/bn_mul.h @@ -0,0 +1,864 @@ +/** + * \file bn_mul.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * Multiply source vector [s] with b, add result + * to destination vector [d] and set carry c. + * + * Currently supports: + * + * . IA-32 (386+) . AMD64 / EM64T + * . IA-32 (SSE2) . Motorola 68000 + * . PowerPC, 32-bit . MicroBlaze + * . PowerPC, 64-bit . TriCore + * . SPARC v8 . ARM v3+ + * . Alpha . MIPS32 + * . C, longlong . C, generic + */ +#ifndef POLARSSL_BN_MUL_H +#define POLARSSL_BN_MUL_H + +#include "bignum.h" + +#if defined(POLARSSL_HAVE_ASM) + +#if defined(__GNUC__) +#if defined(__i386__) + +#define MULADDC_INIT \ + asm( " \ + movl %%ebx, %0; \ + movl %5, %%esi; \ + movl %6, %%edi; \ + movl %7, %%ecx; \ + movl %8, %%ebx; \ + " + +#define MULADDC_CORE \ + " \ + lodsl; \ + mull %%ebx; \ + addl %%ecx, %%eax; \ + adcl $0, %%edx; \ + addl (%%edi), %%eax; \ + adcl $0, %%edx; \ + movl %%edx, %%ecx; \ + stosl; \ + " + +#if defined(POLARSSL_HAVE_SSE2) + +#define MULADDC_HUIT \ + " \ + movd %%ecx, %%mm1; \ + movd %%ebx, %%mm0; \ + movd (%%edi), %%mm3; \ + paddq %%mm3, %%mm1; \ + movd (%%esi), %%mm2; \ + pmuludq %%mm0, %%mm2; \ + movd 4(%%esi), %%mm4; \ + pmuludq %%mm0, %%mm4; \ + movd 8(%%esi), %%mm6; \ + pmuludq %%mm0, %%mm6; \ + movd 12(%%esi), %%mm7; \ + pmuludq %%mm0, %%mm7; \ + paddq %%mm2, %%mm1; \ + movd 4(%%edi), %%mm3; \ + paddq %%mm4, %%mm3; \ + movd 8(%%edi), %%mm5; \ + paddq %%mm6, %%mm5; \ + movd 12(%%edi), %%mm4; \ + paddq %%mm4, %%mm7; \ + movd %%mm1, (%%edi); \ + movd 16(%%esi), %%mm2; \ + pmuludq %%mm0, %%mm2; \ + psrlq $32, %%mm1; \ + movd 20(%%esi), %%mm4; \ + pmuludq %%mm0, %%mm4; \ + paddq %%mm3, %%mm1; \ + movd 24(%%esi), %%mm6; \ + pmuludq %%mm0, %%mm6; \ + movd %%mm1, 4(%%edi); \ + psrlq $32, %%mm1; \ + movd 28(%%esi), %%mm3; \ + pmuludq %%mm0, %%mm3; \ + paddq %%mm5, %%mm1; \ + movd 16(%%edi), %%mm5; \ + paddq %%mm5, %%mm2; \ + movd %%mm1, 8(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm7, %%mm1; \ + movd 20(%%edi), %%mm5; \ + paddq %%mm5, %%mm4; \ + movd %%mm1, 12(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm2, %%mm1; \ + movd 24(%%edi), %%mm5; \ + paddq %%mm5, %%mm6; \ + movd %%mm1, 16(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm4, %%mm1; \ + movd 28(%%edi), %%mm5; \ + paddq %%mm5, %%mm3; \ + movd %%mm1, 20(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm6, %%mm1; \ + movd %%mm1, 24(%%edi); \ + psrlq $32, %%mm1; \ + paddq %%mm3, %%mm1; \ + movd %%mm1, 28(%%edi); \ + addl $32, %%edi; \ + addl $32, %%esi; \ + psrlq $32, %%mm1; \ + movd %%mm1, %%ecx; \ + " + +#define MULADDC_STOP \ + " \ + emms; \ + movl %4, %%ebx; \ + movl %%ecx, %1; \ + movl %%edi, %2; \ + movl %%esi, %3; \ + " \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ecx", "edx", "esi", "edi" \ + ); + +#else + +#define MULADDC_STOP \ + " \ + movl %4, %%ebx; \ + movl %%ecx, %1; \ + movl %%edi, %2; \ + movl %%esi, %3; \ + " \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ecx", "edx", "esi", "edi" \ + ); +#endif /* SSE2 */ +#endif /* i386 */ + +#if defined(__amd64__) || defined (__x86_64__) + +#define MULADDC_INIT \ + asm( "movq %0, %%rsi " :: "m" (s)); \ + asm( "movq %0, %%rdi " :: "m" (d)); \ + asm( "movq %0, %%rcx " :: "m" (c)); \ + asm( "movq %0, %%rbx " :: "m" (b)); \ + asm( "xorq %r8, %r8 " ); + +#define MULADDC_CORE \ + asm( "movq (%rsi),%rax " ); \ + asm( "mulq %rbx " ); \ + asm( "addq $8, %rsi " ); \ + asm( "addq %rcx, %rax " ); \ + asm( "movq %r8, %rcx " ); \ + asm( "adcq $0, %rdx " ); \ + asm( "nop " ); \ + asm( "addq %rax, (%rdi) " ); \ + asm( "adcq %rdx, %rcx " ); \ + asm( "addq $8, %rdi " ); + +#define MULADDC_STOP \ + asm( "movq %%rcx, %0 " : "=m" (c)); \ + asm( "movq %%rdi, %0 " : "=m" (d)); \ + asm( "movq %%rsi, %0 " : "=m" (s) :: \ + "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" ); + +#endif /* AMD64 */ + +#if defined(__mc68020__) || defined(__mcpu32__) + +#define MULADDC_INIT \ + asm( "movl %0, %%a2 " :: "m" (s)); \ + asm( "movl %0, %%a3 " :: "m" (d)); \ + asm( "movl %0, %%d3 " :: "m" (c)); \ + asm( "movl %0, %%d2 " :: "m" (b)); \ + asm( "moveq #0, %d0 " ); + +#define MULADDC_CORE \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "moveq #0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "addxl %d4, %d3 " ); + +#define MULADDC_STOP \ + asm( "movl %%d3, %0 " : "=m" (c)); \ + asm( "movl %%a3, %0 " : "=m" (d)); \ + asm( "movl %%a2, %0 " : "=m" (s) :: \ + "d0", "d1", "d2", "d3", "d4", "a2", "a3" ); + +#define MULADDC_HUIT \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "addxl %d0, %d3 " ); + +#endif /* MC68000 */ + +#if defined(__powerpc__) || defined(__ppc__) +#if defined(__powerpc64__) || defined(__ppc64__) + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( "ld r3, %0 " :: "m" (s)); \ + asm( "ld r4, %0 " :: "m" (d)); \ + asm( "ld r5, %0 " :: "m" (c)); \ + asm( "ld r6, %0 " :: "m" (b)); \ + asm( "addi r3, r3, -8 " ); \ + asm( "addi r4, r4, -8 " ); \ + asm( "addic r5, r5, 0 " ); + +#define MULADDC_CORE \ + asm( "ldu r7, 8(r3) " ); \ + asm( "mulld r8, r7, r6 " ); \ + asm( "mulhdu r9, r7, r6 " ); \ + asm( "adde r8, r8, r5 " ); \ + asm( "ld r7, 8(r4) " ); \ + asm( "addze r5, r9 " ); \ + asm( "addc r8, r8, r7 " ); \ + asm( "stdu r8, 8(r4) " ); + +#define MULADDC_STOP \ + asm( "addze r5, r5 " ); \ + asm( "addi r4, r4, 8 " ); \ + asm( "addi r3, r3, 8 " ); \ + asm( "std r5, %0 " : "=m" (c)); \ + asm( "std r4, %0 " : "=m" (d)); \ + asm( "std r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#else + +#define MULADDC_INIT \ + asm( "ld %%r3, %0 " :: "m" (s)); \ + asm( "ld %%r4, %0 " :: "m" (d)); \ + asm( "ld %%r5, %0 " :: "m" (c)); \ + asm( "ld %%r6, %0 " :: "m" (b)); \ + asm( "addi %r3, %r3, -8 " ); \ + asm( "addi %r4, %r4, -8 " ); \ + asm( "addic %r5, %r5, 0 " ); + +#define MULADDC_CORE \ + asm( "ldu %r7, 8(%r3) " ); \ + asm( "mulld %r8, %r7, %r6 " ); \ + asm( "mulhdu %r9, %r7, %r6 " ); \ + asm( "adde %r8, %r8, %r5 " ); \ + asm( "ld %r7, 8(%r4) " ); \ + asm( "addze %r5, %r9 " ); \ + asm( "addc %r8, %r8, %r7 " ); \ + asm( "stdu %r8, 8(%r4) " ); + +#define MULADDC_STOP \ + asm( "addze %r5, %r5 " ); \ + asm( "addi %r4, %r4, 8 " ); \ + asm( "addi %r3, %r3, 8 " ); \ + asm( "std %%r5, %0 " : "=m" (c)); \ + asm( "std %%r4, %0 " : "=m" (d)); \ + asm( "std %%r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#endif + +#else /* PPC32 */ + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( "lwz r3, %0 " :: "m" (s)); \ + asm( "lwz r4, %0 " :: "m" (d)); \ + asm( "lwz r5, %0 " :: "m" (c)); \ + asm( "lwz r6, %0 " :: "m" (b)); \ + asm( "addi r3, r3, -4 " ); \ + asm( "addi r4, r4, -4 " ); \ + asm( "addic r5, r5, 0 " ); + +#define MULADDC_CORE \ + asm( "lwzu r7, 4(r3) " ); \ + asm( "mullw r8, r7, r6 " ); \ + asm( "mulhwu r9, r7, r6 " ); \ + asm( "adde r8, r8, r5 " ); \ + asm( "lwz r7, 4(r4) " ); \ + asm( "addze r5, r9 " ); \ + asm( "addc r8, r8, r7 " ); \ + asm( "stwu r8, 4(r4) " ); + +#define MULADDC_STOP \ + asm( "addze r5, r5 " ); \ + asm( "addi r4, r4, 4 " ); \ + asm( "addi r3, r3, 4 " ); \ + asm( "stw r5, %0 " : "=m" (c)); \ + asm( "stw r4, %0 " : "=m" (d)); \ + asm( "stw r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#else + +#define MULADDC_INIT \ + asm( "lwz %%r3, %0 " :: "m" (s)); \ + asm( "lwz %%r4, %0 " :: "m" (d)); \ + asm( "lwz %%r5, %0 " :: "m" (c)); \ + asm( "lwz %%r6, %0 " :: "m" (b)); \ + asm( "addi %r3, %r3, -4 " ); \ + asm( "addi %r4, %r4, -4 " ); \ + asm( "addic %r5, %r5, 0 " ); + +#define MULADDC_CORE \ + asm( "lwzu %r7, 4(%r3) " ); \ + asm( "mullw %r8, %r7, %r6 " ); \ + asm( "mulhwu %r9, %r7, %r6 " ); \ + asm( "adde %r8, %r8, %r5 " ); \ + asm( "lwz %r7, 4(%r4) " ); \ + asm( "addze %r5, %r9 " ); \ + asm( "addc %r8, %r8, %r7 " ); \ + asm( "stwu %r8, 4(%r4) " ); + +#define MULADDC_STOP \ + asm( "addze %r5, %r5 " ); \ + asm( "addi %r4, %r4, 4 " ); \ + asm( "addi %r3, %r3, 4 " ); \ + asm( "stw %%r5, %0 " : "=m" (c)); \ + asm( "stw %%r4, %0 " : "=m" (d)); \ + asm( "stw %%r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#endif + +#endif /* PPC32 */ +#endif /* PPC64 */ + +#if defined(__sparc__) && defined(__sparc64__) + +#define MULADDC_INIT \ + asm( \ + " \ + ldx %3, %%o0; \ + ldx %4, %%o1; \ + ld %5, %%o2; \ + ld %6, %%o3; \ + " + +#define MULADDC_CORE \ + " \ + ld [%%o0], %%o4; \ + inc 4, %%o0; \ + ld [%%o1], %%o5; \ + umul %%o3, %%o4, %%o4; \ + addcc %%o4, %%o2, %%o4; \ + rd %%y, %%g1; \ + addx %%g1, 0, %%g1; \ + addcc %%o4, %%o5, %%o4; \ + st %%o4, [%%o1]; \ + addx %%g1, 0, %%o2; \ + inc 4, %%o1; \ + " + +#define MULADDC_STOP \ + " \ + st %%o2, %0; \ + stx %%o1, %1; \ + stx %%o0, %2; \ + " \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "g1", "o0", "o1", "o2", "o3", "o4", \ + "o5" \ + ); +#endif /* SPARCv9 */ + +#if defined(__sparc__) && !defined(__sparc64__) + +#define MULADDC_INIT \ + asm( \ + " \ + ld %3, %%o0; \ + ld %4, %%o1; \ + ld %5, %%o2; \ + ld %6, %%o3; \ + " + +#define MULADDC_CORE \ + " \ + ld [%%o0], %%o4; \ + inc 4, %%o0; \ + ld [%%o1], %%o5; \ + umul %%o3, %%o4, %%o4; \ + addcc %%o4, %%o2, %%o4; \ + rd %%y, %%g1; \ + addx %%g1, 0, %%g1; \ + addcc %%o4, %%o5, %%o4; \ + st %%o4, [%%o1]; \ + addx %%g1, 0, %%o2; \ + inc 4, %%o1; \ + " + +#define MULADDC_STOP \ + " \ + st %%o2, %0; \ + st %%o1, %1; \ + st %%o0, %2; \ + " \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "g1", "o0", "o1", "o2", "o3", "o4", \ + "o5" \ + ); + +#endif /* SPARCv8 */ + +#if defined(__microblaze__) || defined(microblaze) + +#define MULADDC_INIT \ + asm( "lwi r3, %0 " :: "m" (s)); \ + asm( "lwi r4, %0 " :: "m" (d)); \ + asm( "lwi r5, %0 " :: "m" (c)); \ + asm( "lwi r6, %0 " :: "m" (b)); \ + asm( "andi r7, r6, 0xffff" ); \ + asm( "bsrli r6, r6, 16 " ); + +#define MULADDC_CORE \ + asm( "lhui r8, r3, 0 " ); \ + asm( "addi r3, r3, 2 " ); \ + asm( "lhui r9, r3, 0 " ); \ + asm( "addi r3, r3, 2 " ); \ + asm( "mul r10, r9, r6 " ); \ + asm( "mul r11, r8, r7 " ); \ + asm( "mul r12, r9, r7 " ); \ + asm( "mul r13, r8, r6 " ); \ + asm( "bsrli r8, r10, 16 " ); \ + asm( "bsrli r9, r11, 16 " ); \ + asm( "add r13, r13, r8 " ); \ + asm( "add r13, r13, r9 " ); \ + asm( "bslli r10, r10, 16 " ); \ + asm( "bslli r11, r11, 16 " ); \ + asm( "add r12, r12, r10 " ); \ + asm( "addc r13, r13, r0 " ); \ + asm( "add r12, r12, r11 " ); \ + asm( "addc r13, r13, r0 " ); \ + asm( "lwi r10, r4, 0 " ); \ + asm( "add r12, r12, r10 " ); \ + asm( "addc r13, r13, r0 " ); \ + asm( "add r12, r12, r5 " ); \ + asm( "addc r5, r13, r0 " ); \ + asm( "swi r12, r4, 0 " ); \ + asm( "addi r4, r4, 4 " ); + +#define MULADDC_STOP \ + asm( "swi r5, %0 " : "=m" (c)); \ + asm( "swi r4, %0 " : "=m" (d)); \ + asm( "swi r3, %0 " : "=m" (s) :: \ + "r3", "r4" , "r5" , "r6" , "r7" , "r8" , \ + "r9", "r10", "r11", "r12", "r13" ); + +#endif /* MicroBlaze */ + +#if defined(__tricore__) + +#define MULADDC_INIT \ + asm( "ld.a %%a2, %0 " :: "m" (s)); \ + asm( "ld.a %%a3, %0 " :: "m" (d)); \ + asm( "ld.w %%d4, %0 " :: "m" (c)); \ + asm( "ld.w %%d1, %0 " :: "m" (b)); \ + asm( "xor %d5, %d5 " ); + +#define MULADDC_CORE \ + asm( "ld.w %d0, [%a2+] " ); \ + asm( "madd.u %e2, %e4, %d0, %d1 " ); \ + asm( "ld.w %d0, [%a3] " ); \ + asm( "addx %d2, %d2, %d0 " ); \ + asm( "addc %d3, %d3, 0 " ); \ + asm( "mov %d4, %d3 " ); \ + asm( "st.w [%a3+], %d2 " ); + +#define MULADDC_STOP \ + asm( "st.w %0, %%d4 " : "=m" (c)); \ + asm( "st.a %0, %%a3 " : "=m" (d)); \ + asm( "st.a %0, %%a2 " : "=m" (s) :: \ + "d0", "d1", "e2", "d4", "a2", "a3" ); + +#endif /* TriCore */ + +#if defined(__arm__) + +#if defined(__thumb__) && !defined(__thumb2__) + +#define MULADDC_INIT \ + asm( \ + " \ + ldr r0, %3; \ + ldr r1, %4; \ + ldr r2, %5; \ + ldr r3, %6; \ + lsr r7, r3, #16; \ + mov r9, r7; \ + lsl r7, r3, #16; \ + lsr r7, r7, #16; \ + mov r8, r7; \ + " + +#define MULADDC_CORE \ + " \ + ldmia r0!, {r6}; \ + lsr r7, r6, #16; \ + lsl r6, r6, #16; \ + lsr r6, r6, #16; \ + mov r4, r8; \ + mul r4, r6; \ + mov r3, r9; \ + mul r6, r3; \ + mov r5, r9; \ + mul r5, r7; \ + mov r3, r8; \ + mul r7, r3; \ + lsr r3, r6, #16; \ + add r5, r5, r3; \ + lsr r3, r7, #16; \ + add r5, r5, r3; \ + add r4, r4, r2; \ + mov r2, #0; \ + adc r5, r2; \ + lsl r3, r6, #16; \ + add r4, r4, r3; \ + adc r5, r2; \ + lsl r3, r7, #16; \ + add r4, r4, r3; \ + adc r5, r2; \ + ldr r3, [r1]; \ + add r4, r4, r3; \ + adc r2, r5; \ + stmia r1!, {r4}; \ + " + +#define MULADDC_STOP \ + " \ + str r2, %0; \ + str r1, %1; \ + str r0, %2; \ + " \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "r8", "r9", "cc" \ + ); + +#else + +#define MULADDC_INIT \ + asm( \ + " \ + ldr r0, %3; \ + ldr r1, %4; \ + ldr r2, %5; \ + ldr r3, %6; \ + " + +#define MULADDC_CORE \ + " \ + ldr r4, [r0], #4; \ + mov r5, #0; \ + ldr r6, [r1]; \ + umlal r2, r5, r3, r4; \ + adds r7, r6, r2; \ + adc r2, r5, #0; \ + str r7, [r1], #4; \ + " + +#define MULADDC_STOP \ + " \ + str r2, %0; \ + str r1, %1; \ + str r0, %2; \ + " \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "cc" \ + ); + +#endif /* Thumb */ + +#endif /* ARMv3 */ + +#if defined(__alpha__) + +#define MULADDC_INIT \ + asm( "ldq $1, %0 " :: "m" (s)); \ + asm( "ldq $2, %0 " :: "m" (d)); \ + asm( "ldq $3, %0 " :: "m" (c)); \ + asm( "ldq $4, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ldq $6, 0($1) " ); \ + asm( "addq $1, 8, $1 " ); \ + asm( "mulq $6, $4, $7 " ); \ + asm( "umulh $6, $4, $6 " ); \ + asm( "addq $7, $3, $7 " ); \ + asm( "cmpult $7, $3, $3 " ); \ + asm( "ldq $5, 0($2) " ); \ + asm( "addq $7, $5, $7 " ); \ + asm( "cmpult $7, $5, $5 " ); \ + asm( "stq $7, 0($2) " ); \ + asm( "addq $2, 8, $2 " ); \ + asm( "addq $6, $3, $3 " ); \ + asm( "addq $5, $3, $3 " ); + +#define MULADDC_STOP \ + asm( "stq $3, %0 " : "=m" (c)); \ + asm( "stq $2, %0 " : "=m" (d)); \ + asm( "stq $1, %0 " : "=m" (s) :: \ + "$1", "$2", "$3", "$4", "$5", "$6", "$7" ); + +#endif /* Alpha */ + +#if defined(__mips__) + +#define MULADDC_INIT \ + asm( "lw $10, %0 " :: "m" (s)); \ + asm( "lw $11, %0 " :: "m" (d)); \ + asm( "lw $12, %0 " :: "m" (c)); \ + asm( "lw $13, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "lw $14, 0($10) " ); \ + asm( "multu $13, $14 " ); \ + asm( "addi $10, $10, 4 " ); \ + asm( "mflo $14 " ); \ + asm( "mfhi $9 " ); \ + asm( "addu $14, $12, $14 " ); \ + asm( "lw $15, 0($11) " ); \ + asm( "sltu $12, $14, $12 " ); \ + asm( "addu $15, $14, $15 " ); \ + asm( "sltu $14, $15, $14 " ); \ + asm( "addu $12, $12, $9 " ); \ + asm( "sw $15, 0($11) " ); \ + asm( "addu $12, $12, $14 " ); \ + asm( "addi $11, $11, 4 " ); + +#define MULADDC_STOP \ + asm( "sw $12, %0 " : "=m" (c)); \ + asm( "sw $11, %0 " : "=m" (d)); \ + asm( "sw $10, %0 " : "=m" (s) :: \ + "$9", "$10", "$11", "$12", "$13", "$14", "$15" ); + +#endif /* MIPS */ +#endif /* GNUC */ + +#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + +#define MULADDC_INIT \ + __asm mov esi, s \ + __asm mov edi, d \ + __asm mov ecx, c \ + __asm mov ebx, b + +#define MULADDC_CORE \ + __asm lodsd \ + __asm mul ebx \ + __asm add eax, ecx \ + __asm adc edx, 0 \ + __asm add eax, [edi] \ + __asm adc edx, 0 \ + __asm mov ecx, edx \ + __asm stosd + +#if defined(POLARSSL_HAVE_SSE2) + +#define EMIT __asm _emit + +#define MULADDC_HUIT \ + EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ + EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ + EMIT 0x0F EMIT 0x6E EMIT 0x1F \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x16 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ + EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ + EMIT 0x0F EMIT 0x7E EMIT 0x0F \ + EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ + EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ + EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x7E EMIT 0xC9 + +#define MULADDC_STOP \ + EMIT 0x0F EMIT 0x77 \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#else + +#define MULADDC_STOP \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#endif /* SSE2 */ +#endif /* MSVC */ + +#endif /* POLARSSL_HAVE_ASM */ + +#if !defined(MULADDC_CORE) +#if defined(POLARSSL_HAVE_UDBL) + +#define MULADDC_INIT \ +{ \ + t_udbl r; \ + t_uint r0, r1; + +#define MULADDC_CORE \ + r = *(s++) * (t_udbl) b; \ + r0 = r; \ + r1 = r >> biL; \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#else +#define MULADDC_INIT \ +{ \ + t_uint s0, s1, b0, b1; \ + t_uint r0, r1, rx, ry; \ + b0 = ( b << biH ) >> biH; \ + b1 = ( b >> biH ); + +#define MULADDC_CORE \ + s0 = ( *s << biH ) >> biH; \ + s1 = ( *s >> biH ); s++; \ + rx = s0 * b1; r0 = s0 * b0; \ + ry = s1 * b0; r1 = s1 * b1; \ + r1 += ( rx >> biH ); \ + r1 += ( ry >> biH ); \ + rx <<= biH; ry <<= biH; \ + r0 += rx; r1 += (r0 < rx); \ + r0 += ry; r1 += (r0 < ry); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#endif /* C (generic) */ +#endif /* C (longlong) */ + +#endif /* bn_mul.h */ diff --git a/src/libpolarssl/camellia.c b/src/libpolarssl/camellia.c new file mode 100644 index 0000000..cbdeab6 --- /dev/null +++ b/src/libpolarssl/camellia.c @@ -0,0 +1,1035 @@ +/* + * Camellia implementation + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The Camellia block cipher was designed by NTT and Mitsubishi Electric + * Corporation. + * + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/01espec.pdf + */ + +#include "config.h" + +#if defined(POLARSSL_CAMELLIA_C) + +#include "camellia.h" + +#if !defined(POLARSSL_CAMELLIA_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +static const unsigned char SIGMA_CHARS[6][8] = +{ + { 0xa0, 0x9e, 0x66, 0x7f, 0x3b, 0xcc, 0x90, 0x8b }, + { 0xb6, 0x7a, 0xe8, 0x58, 0x4c, 0xaa, 0x73, 0xb2 }, + { 0xc6, 0xef, 0x37, 0x2f, 0xe9, 0x4f, 0x82, 0xbe }, + { 0x54, 0xff, 0x53, 0xa5, 0xf1, 0xd3, 0x6f, 0x1c }, + { 0x10, 0xe5, 0x27, 0xfa, 0xde, 0x68, 0x2d, 0x1d }, + { 0xb0, 0x56, 0x88, 0xc2, 0xb3, 0xe6, 0xc1, 0xfd } +}; + +#if defined(POLARSSL_CAMELLIA_SMALL_MEMORY) + +static const unsigned char FSb[256] = +{ + 112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65, + 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189, + 134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26, + 166,225, 57,202,213, 71, 93, 61,217, 1, 90,214, 81, 86,108, 77, + 139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153, + 223, 76,203,194, 52,126,118, 5,109,183,169, 49,209, 23, 4,215, + 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34, + 254, 68,207,178,195,181,122,145, 36, 8,232,168, 96,252,105, 80, + 170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210, + 16,196, 0, 72,163,247,117,219,138, 3,230,218, 9, 63,221,148, + 135, 92,131, 2,205, 74,144, 51,115,103,246,243,157,127,191,226, + 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46, + 233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89, + 120,152, 6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250, + 114, 7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164, + 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158 +}; + +#define SBOX1(n) FSb[(n)] +#define SBOX2(n) (unsigned char)((FSb[(n)] >> 7 ^ FSb[(n)] << 1) & 0xff) +#define SBOX3(n) (unsigned char)((FSb[(n)] >> 1 ^ FSb[(n)] << 7) & 0xff) +#define SBOX4(n) FSb[((n) << 1 ^ (n) >> 7) &0xff] + +#else + +static const unsigned char FSb[256] = +{ + 112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65, + 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189, + 134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26, + 166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77, + 139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153, + 223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215, + 20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34, + 254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80, + 170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210, + 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148, + 135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226, + 82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46, + 233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89, + 120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250, + 114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164, + 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158 +}; + +static const unsigned char FSb2[256] = +{ + 224, 5, 88, 217, 103, 78, 129, 203, 201, 11, 174, 106, 213, 24, 93, 130, + 70, 223, 214, 39, 138, 50, 75, 66, 219, 28, 158, 156, 58, 202, 37, 123, + 13, 113, 95, 31, 248, 215, 62, 157, 124, 96, 185, 190, 188, 139, 22, 52, + 77, 195, 114, 149, 171, 142, 186, 122, 179, 2, 180, 173, 162, 172, 216, 154, + 23, 26, 53, 204, 247, 153, 97, 90, 232, 36, 86, 64, 225, 99, 9, 51, + 191, 152, 151, 133, 104, 252, 236, 10, 218, 111, 83, 98, 163, 46, 8, 175, + 40, 176, 116, 194, 189, 54, 34, 56, 100, 30, 57, 44, 166, 48, 229, 68, + 253, 136, 159, 101, 135, 107, 244, 35, 72, 16, 209, 81, 192, 249, 210, 160, + 85, 161, 65, 250, 67, 19, 196, 47, 168, 182, 60, 43, 193, 255, 200, 165, + 32, 137, 0, 144, 71, 239, 234, 183, 21, 6, 205, 181, 18, 126, 187, 41, + 15, 184, 7, 4, 155, 148, 33, 102, 230, 206, 237, 231, 59, 254, 127, 197, + 164, 55, 177, 76, 145, 110, 141, 118, 3, 45, 222, 150, 38, 125, 198, 92, + 211, 242, 79, 25, 63, 220, 121, 29, 82, 235, 243, 109, 94, 251, 105, 178, + 240, 49, 12, 212, 207, 140, 226, 117, 169, 74, 87, 132, 17, 69, 27, 245, + 228, 14, 115, 170, 241, 221, 89, 20, 108, 146, 84, 208, 120, 112, 227, 73, + 128, 80, 167, 246, 119, 147, 134, 131, 42, 199, 91, 233, 238, 143, 1, 61 +}; + +static const unsigned char FSb3[256] = +{ + 56, 65, 22, 118, 217, 147, 96, 242, 114, 194, 171, 154, 117, 6, 87, 160, + 145, 247, 181, 201, 162, 140, 210, 144, 246, 7, 167, 39, 142, 178, 73, 222, + 67, 92, 215, 199, 62, 245, 143, 103, 31, 24, 110, 175, 47, 226, 133, 13, + 83, 240, 156, 101, 234, 163, 174, 158, 236, 128, 45, 107, 168, 43, 54, 166, + 197, 134, 77, 51, 253, 102, 88, 150, 58, 9, 149, 16, 120, 216, 66, 204, + 239, 38, 229, 97, 26, 63, 59, 130, 182, 219, 212, 152, 232, 139, 2, 235, + 10, 44, 29, 176, 111, 141, 136, 14, 25, 135, 78, 11, 169, 12, 121, 17, + 127, 34, 231, 89, 225, 218, 61, 200, 18, 4, 116, 84, 48, 126, 180, 40, + 85, 104, 80, 190, 208, 196, 49, 203, 42, 173, 15, 202, 112, 255, 50, 105, + 8, 98, 0, 36, 209, 251, 186, 237, 69, 129, 115, 109, 132, 159, 238, 74, + 195, 46, 193, 1, 230, 37, 72, 153, 185, 179, 123, 249, 206, 191, 223, 113, + 41, 205, 108, 19, 100, 155, 99, 157, 192, 75, 183, 165, 137, 95, 177, 23, + 244, 188, 211, 70, 207, 55, 94, 71, 148, 250, 252, 91, 151, 254, 90, 172, + 60, 76, 3, 53, 243, 35, 184, 93, 106, 146, 213, 33, 68, 81, 198, 125, + 57, 131, 220, 170, 124, 119, 86, 5, 27, 164, 21, 52, 30, 28, 248, 82, + 32, 20, 233, 189, 221, 228, 161, 224, 138, 241, 214, 122, 187, 227, 64, 79 +}; + +static const unsigned char FSb4[256] = +{ + 112, 44, 179, 192, 228, 87, 234, 174, 35, 107, 69, 165, 237, 79, 29, 146, + 134, 175, 124, 31, 62, 220, 94, 11, 166, 57, 213, 93, 217, 90, 81, 108, + 139, 154, 251, 176, 116, 43, 240, 132, 223, 203, 52, 118, 109, 169, 209, 4, + 20, 58, 222, 17, 50, 156, 83, 242, 254, 207, 195, 122, 36, 232, 96, 105, + 170, 160, 161, 98, 84, 30, 224, 100, 16, 0, 163, 117, 138, 230, 9, 221, + 135, 131, 205, 144, 115, 246, 157, 191, 82, 216, 200, 198, 129, 111, 19, 99, + 233, 167, 159, 188, 41, 249, 47, 180, 120, 6, 231, 113, 212, 171, 136, 141, + 114, 185, 248, 172, 54, 42, 60, 241, 64, 211, 187, 67, 21, 173, 119, 128, + 130, 236, 39, 229, 133, 53, 12, 65, 239, 147, 25, 33, 14, 78, 101, 189, + 184, 143, 235, 206, 48, 95, 197, 26, 225, 202, 71, 61, 1, 214, 86, 77, + 13, 102, 204, 45, 18, 32, 177, 153, 76, 194, 126, 5, 183, 49, 23, 215, + 88, 97, 27, 28, 15, 22, 24, 34, 68, 178, 181, 145, 8, 168, 252, 80, + 208, 125, 137, 151, 91, 149, 255, 210, 196, 72, 247, 219, 3, 218, 63, 148, + 92, 2, 74, 51, 103, 243, 127, 226, 155, 38, 55, 59, 150, 75, 190, 46, + 121, 140, 110, 142, 245, 182, 253, 89, 152, 106, 70, 186, 37, 66, 162, 250, + 7, 85, 238, 10, 73, 104, 56, 164, 40, 123, 201, 193, 227, 244, 199, 158 +}; + +#define SBOX1(n) FSb[(n)] +#define SBOX2(n) FSb2[(n)] +#define SBOX3(n) FSb3[(n)] +#define SBOX4(n) FSb4[(n)] + +#endif + +static const unsigned char shifts[2][4][4] = +{ + { + { 1, 1, 1, 1 }, /* KL */ + { 0, 0, 0, 0 }, /* KR */ + { 1, 1, 1, 1 }, /* KA */ + { 0, 0, 0, 0 } /* KB */ + }, + { + { 1, 0, 1, 1 }, /* KL */ + { 1, 1, 0, 1 }, /* KR */ + { 1, 1, 1, 0 }, /* KA */ + { 1, 1, 0, 1 } /* KB */ + } +}; + +static const signed char indexes[2][4][20] = +{ + { + { 0, 1, 2, 3, 8, 9, 10, 11, 38, 39, + 36, 37, 23, 20, 21, 22, 27, -1, -1, 26 }, /* KL -> RK */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /* KR -> RK */ + { 4, 5, 6, 7, 12, 13, 14, 15, 16, 17, + 18, 19, -1, 24, 25, -1, 31, 28, 29, 30 }, /* KA -> RK */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } /* KB -> RK */ + }, + { + { 0, 1, 2, 3, 61, 62, 63, 60, -1, -1, + -1, -1, 27, 24, 25, 26, 35, 32, 33, 34 }, /* KL -> RK */ + { -1, -1, -1, -1, 8, 9, 10, 11, 16, 17, + 18, 19, -1, -1, -1, -1, 39, 36, 37, 38 }, /* KR -> RK */ + { -1, -1, -1, -1, 12, 13, 14, 15, 58, 59, + 56, 57, 31, 28, 29, 30, -1, -1, -1, -1 }, /* KA -> RK */ + { 4, 5, 6, 7, 65, 66, 67, 64, 20, 21, + 22, 23, -1, -1, -1, -1, 43, 40, 41, 42 } /* KB -> RK */ + } +}; + +static const signed char transposes[2][20] = +{ + { + 21, 22, 23, 20, + -1, -1, -1, -1, + 18, 19, 16, 17, + 11, 8, 9, 10, + 15, 12, 13, 14 + }, + { + 25, 26, 27, 24, + 29, 30, 31, 28, + 18, 19, 16, 17, + -1, -1, -1, -1, + -1, -1, -1, -1 + } +}; + +/* Shift macro for 128 bit strings with rotation smaller than 32 bits (!) */ +#define ROTL(DEST, SRC, SHIFT) \ +{ \ + (DEST)[0] = (SRC)[0] << (SHIFT) ^ (SRC)[1] >> (32 - (SHIFT)); \ + (DEST)[1] = (SRC)[1] << (SHIFT) ^ (SRC)[2] >> (32 - (SHIFT)); \ + (DEST)[2] = (SRC)[2] << (SHIFT) ^ (SRC)[3] >> (32 - (SHIFT)); \ + (DEST)[3] = (SRC)[3] << (SHIFT) ^ (SRC)[0] >> (32 - (SHIFT)); \ +} + +#define FL(XL, XR, KL, KR) \ +{ \ + (XR) = ((((XL) & (KL)) << 1) | (((XL) & (KL)) >> 31)) ^ (XR); \ + (XL) = ((XR) | (KR)) ^ (XL); \ +} + +#define FLInv(YL, YR, KL, KR) \ +{ \ + (YL) = ((YR) | (KR)) ^ (YL); \ + (YR) = ((((YL) & (KL)) << 1) | (((YL) & (KL)) >> 31)) ^ (YR); \ +} + +#define SHIFT_AND_PLACE(INDEX, OFFSET) \ +{ \ + TK[0] = KC[(OFFSET) * 4 + 0]; \ + TK[1] = KC[(OFFSET) * 4 + 1]; \ + TK[2] = KC[(OFFSET) * 4 + 2]; \ + TK[3] = KC[(OFFSET) * 4 + 3]; \ + \ + for ( i = 1; i <= 4; i++ ) \ + if (shifts[(INDEX)][(OFFSET)][i -1]) \ + ROTL(TK + i * 4, TK, (15 * i) % 32); \ + \ + for ( i = 0; i < 20; i++ ) \ + if (indexes[(INDEX)][(OFFSET)][i] != -1) { \ + RK[indexes[(INDEX)][(OFFSET)][i]] = TK[ i ]; \ + } \ +} + +static void camellia_feistel(const uint32_t x[2], const uint32_t k[2], uint32_t z[2]) +{ + uint32_t I0, I1; + I0 = x[0] ^ k[0]; + I1 = x[1] ^ k[1]; + + I0 = (SBOX1((I0 >> 24) & 0xFF) << 24) | + (SBOX2((I0 >> 16) & 0xFF) << 16) | + (SBOX3((I0 >> 8) & 0xFF) << 8) | + (SBOX4((I0 ) & 0xFF) ); + I1 = (SBOX2((I1 >> 24) & 0xFF) << 24) | + (SBOX3((I1 >> 16) & 0xFF) << 16) | + (SBOX4((I1 >> 8) & 0xFF) << 8) | + (SBOX1((I1 ) & 0xFF) ); + + I0 ^= (I1 << 8) | (I1 >> 24); + I1 ^= (I0 << 16) | (I0 >> 16); + I0 ^= (I1 >> 8) | (I1 << 24); + I1 ^= (I0 >> 8) | (I0 << 24); + + z[0] ^= I1; + z[1] ^= I0; +} + +/* + * Camellia key schedule (encryption) + */ +int camellia_setkey_enc( camellia_context *ctx, const unsigned char *key, unsigned int keysize ) +{ + int idx; + size_t i; + uint32_t *RK; + unsigned char t[64]; + uint32_t SIGMA[6][2]; + uint32_t KC[16]; + uint32_t TK[20]; + + RK = ctx->rk; + + memset(t, 0, 64); + memset(RK, 0, sizeof(ctx->rk)); + + switch( keysize ) + { + case 128: ctx->nr = 3; idx = 0; break; + case 192: + case 256: ctx->nr = 4; idx = 1; break; + default : return( POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH ); + } + + for( i = 0; i < keysize / 8; ++i) + t[i] = key[i]; + + if (keysize == 192) { + for (i = 0; i < 8; i++) + t[24 + i] = ~t[16 + i]; + } + + /* + * Prepare SIGMA values + */ + for (i = 0; i < 6; i++) { + GET_UINT32_BE(SIGMA[i][0], SIGMA_CHARS[i], 0); + GET_UINT32_BE(SIGMA[i][1], SIGMA_CHARS[i], 4); + } + + /* + * Key storage in KC + * Order: KL, KR, KA, KB + */ + memset(KC, 0, sizeof(KC)); + + /* Store KL, KR */ + for (i = 0; i < 8; i++) + GET_UINT32_BE(KC[i], t, i * 4); + + /* Generate KA */ + for( i = 0; i < 4; ++i) + KC[8 + i] = KC[i] ^ KC[4 + i]; + + camellia_feistel(KC + 8, SIGMA[0], KC + 10); + camellia_feistel(KC + 10, SIGMA[1], KC + 8); + + for( i = 0; i < 4; ++i) + KC[8 + i] ^= KC[i]; + + camellia_feistel(KC + 8, SIGMA[2], KC + 10); + camellia_feistel(KC + 10, SIGMA[3], KC + 8); + + if (keysize > 128) { + /* Generate KB */ + for( i = 0; i < 4; ++i) + KC[12 + i] = KC[4 + i] ^ KC[8 + i]; + + camellia_feistel(KC + 12, SIGMA[4], KC + 14); + camellia_feistel(KC + 14, SIGMA[5], KC + 12); + } + + /* + * Generating subkeys + */ + + /* Manipulating KL */ + SHIFT_AND_PLACE(idx, 0); + + /* Manipulating KR */ + if (keysize > 128) { + SHIFT_AND_PLACE(idx, 1); + } + + /* Manipulating KA */ + SHIFT_AND_PLACE(idx, 2); + + /* Manipulating KB */ + if (keysize > 128) { + SHIFT_AND_PLACE(idx, 3); + } + + /* Do transpositions */ + for ( i = 0; i < 20; i++ ) { + if (transposes[idx][i] != -1) { + RK[32 + 12 * idx + i] = RK[transposes[idx][i]]; + } + } + + return( 0 ); +} + +/* + * Camellia key schedule (decryption) + */ +int camellia_setkey_dec( camellia_context *ctx, const unsigned char *key, unsigned int keysize ) +{ + int idx; + size_t i; + camellia_context cty; + uint32_t *RK; + uint32_t *SK; + int ret; + + switch( keysize ) + { + case 128: ctx->nr = 3; idx = 0; break; + case 192: + case 256: ctx->nr = 4; idx = 1; break; + default : return( POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH ); + } + + RK = ctx->rk; + + ret = camellia_setkey_enc(&cty, key, keysize); + if( ret != 0 ) + return( ret ); + + SK = cty.rk + 24 * 2 + 8 * idx * 2; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for (i = 22 + 8 * idx, SK -= 6; i > 0; i--, SK -= 4) + { + *RK++ = *SK++; + *RK++ = *SK++; + } + + SK -= 2; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + memset( &cty, 0, sizeof( camellia_context ) ); + + return( 0 ); +} + +/* + * Camellia-ECB block encryption/decryption + */ +int camellia_crypt_ecb( camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int NR; + uint32_t *RK, X[4]; + + ( (void) mode ); + + NR = ctx->nr; + RK = ctx->rk; + + GET_UINT32_BE( X[0], input, 0 ); + GET_UINT32_BE( X[1], input, 4 ); + GET_UINT32_BE( X[2], input, 8 ); + GET_UINT32_BE( X[3], input, 12 ); + + X[0] ^= *RK++; + X[1] ^= *RK++; + X[2] ^= *RK++; + X[3] ^= *RK++; + + while (NR) { + --NR; + camellia_feistel(X, RK, X + 2); + RK += 2; + camellia_feistel(X + 2, RK, X); + RK += 2; + camellia_feistel(X, RK, X + 2); + RK += 2; + camellia_feistel(X + 2, RK, X); + RK += 2; + camellia_feistel(X, RK, X + 2); + RK += 2; + camellia_feistel(X + 2, RK, X); + RK += 2; + + if (NR) { + FL(X[0], X[1], RK[0], RK[1]); + RK += 2; + FLInv(X[2], X[3], RK[0], RK[1]); + RK += 2; + } + } + + X[2] ^= *RK++; + X[3] ^= *RK++; + X[0] ^= *RK++; + X[1] ^= *RK++; + + PUT_UINT32_BE( X[2], output, 0 ); + PUT_UINT32_BE( X[3], output, 4 ); + PUT_UINT32_BE( X[0], output, 8 ); + PUT_UINT32_BE( X[1], output, 12 ); + + return( 0 ); +} + +/* + * Camellia-CBC buffer encryption/decryption + */ +int camellia_crypt_cbc( camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + + if( length % 16 ) + return( POLARSSL_ERR_CAMELLIA_INVALID_INPUT_LENGTH ); + + if( mode == CAMELLIA_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + camellia_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + camellia_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + + return( 0 ); +} + +#if defined(POLARSSL_CIPHER_MODE_CFB) +/* + * Camellia-CFB128 buffer encryption/decryption + */ +int camellia_crypt_cfb128( camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == CAMELLIA_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + camellia_crypt_ecb( ctx, CAMELLIA_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = (n + 1) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + camellia_crypt_ecb( ctx, CAMELLIA_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = (n + 1) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +/* + * Camellia-CTR buffer encryption/decryption + */ +int camellia_crypt_ctr( camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + camellia_crypt_ecb( ctx, CAMELLIA_ENCRYPT, nonce_counter, stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = (n + 1) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* POLARSSL_CIPHER_MODE_CTR */ +#endif /* !POLARSSL_CAMELLIA_ALT */ + +#if defined(POLARSSL_SELF_TEST) + +#include + +/* + * Camellia test vectors from: + * + * http://info.isl.ntt.co.jp/crypt/eng/camellia/technology.html: + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/intermediate.txt + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/t_camellia.txt + * (For each bitlength: Key 0, Nr 39) + */ +#define CAMELLIA_TESTS_ECB 2 + +static const unsigned char camellia_test_ecb_key[3][CAMELLIA_TESTS_ECB][32] = +{ + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, +}; + +static const unsigned char camellia_test_ecb_plain[CAMELLIA_TESTS_ECB][16] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char camellia_test_ecb_cipher[3][CAMELLIA_TESTS_ECB][16] = +{ + { + { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73, + 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 }, + { 0x38, 0x3C, 0x6C, 0x2A, 0xAB, 0xEF, 0x7F, 0xDE, + 0x25, 0xCD, 0x47, 0x0B, 0xF7, 0x74, 0xA3, 0x31 } + }, + { + { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8, + 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 }, + { 0xD1, 0x76, 0x3F, 0xC0, 0x19, 0xD7, 0x7C, 0xC9, + 0x30, 0xBF, 0xF2, 0xA5, 0x6F, 0x7C, 0x93, 0x64 } + }, + { + { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c, + 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 }, + { 0x05, 0x03, 0xFB, 0x10, 0xAB, 0x24, 0x1E, 0x7C, + 0xF4, 0x5D, 0x8C, 0xDE, 0xEE, 0x47, 0x43, 0x35 } + } +}; + +#define CAMELLIA_TESTS_CBC 3 + +static const unsigned char camellia_test_cbc_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C } + , + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B } + , + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char camellia_test_cbc_iv[16] = + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F } +; + +static const unsigned char camellia_test_cbc_plain[CAMELLIA_TESTS_CBC][16] = +{ + { 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A }, + { 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51 }, + { 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF } + +}; + +static const unsigned char camellia_test_cbc_cipher[3][CAMELLIA_TESTS_CBC][16] = +{ + { + { 0x16, 0x07, 0xCF, 0x49, 0x4B, 0x36, 0xBB, 0xF0, + 0x0D, 0xAE, 0xB0, 0xB5, 0x03, 0xC8, 0x31, 0xAB }, + { 0xA2, 0xF2, 0xCF, 0x67, 0x16, 0x29, 0xEF, 0x78, + 0x40, 0xC5, 0xA5, 0xDF, 0xB5, 0x07, 0x48, 0x87 }, + { 0x0F, 0x06, 0x16, 0x50, 0x08, 0xCF, 0x8B, 0x8B, + 0x5A, 0x63, 0x58, 0x63, 0x62, 0x54, 0x3E, 0x54 } + }, + { + { 0x2A, 0x48, 0x30, 0xAB, 0x5A, 0xC4, 0xA1, 0xA2, + 0x40, 0x59, 0x55, 0xFD, 0x21, 0x95, 0xCF, 0x93 }, + { 0x5D, 0x5A, 0x86, 0x9B, 0xD1, 0x4C, 0xE5, 0x42, + 0x64, 0xF8, 0x92, 0xA6, 0xDD, 0x2E, 0xC3, 0xD5 }, + { 0x37, 0xD3, 0x59, 0xC3, 0x34, 0x98, 0x36, 0xD8, + 0x84, 0xE3, 0x10, 0xAD, 0xDF, 0x68, 0xC4, 0x49 } + }, + { + { 0xE6, 0xCF, 0xA3, 0x5F, 0xC0, 0x2B, 0x13, 0x4A, + 0x4D, 0x2C, 0x0B, 0x67, 0x37, 0xAC, 0x3E, 0xDA }, + { 0x36, 0xCB, 0xEB, 0x73, 0xBD, 0x50, 0x4B, 0x40, + 0x70, 0xB1, 0xB7, 0xDE, 0x2B, 0x21, 0xEB, 0x50 }, + { 0xE3, 0x1A, 0x60, 0x55, 0x29, 0x7D, 0x96, 0xCA, + 0x33, 0x30, 0xCD, 0xF1, 0xB1, 0x86, 0x0A, 0x83 } + } +}; + +#if defined(POLARSSL_CIPHER_MODE_CTR) +/* + * Camellia-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc5528.html + */ + +static const unsigned char camellia_test_ctr_key[3][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char camellia_test_ctr_nonce_counter[3][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char camellia_test_ctr_pt[3][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char camellia_test_ctr_ct[3][48] = +{ + { 0xD0, 0x9D, 0xC2, 0x9A, 0x82, 0x14, 0x61, 0x9A, + 0x20, 0x87, 0x7C, 0x76, 0xDB, 0x1F, 0x0B, 0x3F }, + { 0xDB, 0xF3, 0xC7, 0x8D, 0xC0, 0x83, 0x96, 0xD4, + 0xDA, 0x7C, 0x90, 0x77, 0x65, 0xBB, 0xCB, 0x44, + 0x2B, 0x8E, 0x8E, 0x0F, 0x31, 0xF0, 0xDC, 0xA7, + 0x2C, 0x74, 0x17, 0xE3, 0x53, 0x60, 0xE0, 0x48 }, + { 0xB1, 0x9D, 0x1F, 0xCD, 0xCB, 0x75, 0xEB, 0x88, + 0x2F, 0x84, 0x9C, 0xE2, 0x4D, 0x85, 0xCF, 0x73, + 0x9C, 0xE6, 0x4B, 0x2B, 0x5C, 0x9D, 0x73, 0xF1, + 0x4F, 0x2D, 0x5D, 0x9D, 0xCE, 0x98, 0x89, 0xCD, + 0xDF, 0x50, 0x86, 0x96 } +}; + +static const int camellia_test_ctr_len[3] = + { 16, 32, 36 }; +#endif /* POLARSSL_CIPHER_MODE_CTR */ + +/* + * Checkup routine + */ +int camellia_self_test( int verbose ) +{ + int i, j, u, v; + unsigned char key[32]; + unsigned char buf[64]; + unsigned char src[16]; + unsigned char dst[16]; + unsigned char iv[16]; +#if defined(POLARSSL_CIPHER_MODE_CTR) + size_t offset, len; + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + + camellia_context ctx; + + memset( key, 0, 32 ); + + for (j = 0; j < 6; j++) { + u = j >> 1; + v = j & 1; + + if( verbose != 0 ) + printf( " CAMELLIA-ECB-%3d (%s): ", 128 + u * 64, + (v == CAMELLIA_DECRYPT) ? "dec" : "enc"); + + for (i = 0; i < CAMELLIA_TESTS_ECB; i++ ) { + memcpy( key, camellia_test_ecb_key[u][i], 16 + 8 * u); + + if (v == CAMELLIA_DECRYPT) { + camellia_setkey_dec(&ctx, key, 128 + u * 64); + memcpy(src, camellia_test_ecb_cipher[u][i], 16); + memcpy(dst, camellia_test_ecb_plain[i], 16); + } else { /* CAMELLIA_ENCRYPT */ + camellia_setkey_enc(&ctx, key, 128 + u * 64); + memcpy(src, camellia_test_ecb_plain[i], 16); + memcpy(dst, camellia_test_ecb_cipher[u][i], 16); + } + + camellia_crypt_ecb(&ctx, v, src, buf); + + if( memcmp( buf, dst, 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + /* + * CBC mode + */ + for( j = 0; j < 6; j++ ) + { + u = j >> 1; + v = j & 1; + + if( verbose != 0 ) + printf( " CAMELLIA-CBC-%3d (%s): ", 128 + u * 64, + ( v == CAMELLIA_DECRYPT ) ? "dec" : "enc" ); + + memcpy( src, camellia_test_cbc_iv, 16); + memcpy( dst, camellia_test_cbc_iv, 16); + memcpy( key, camellia_test_cbc_key[u], 16 + 8 * u); + + if (v == CAMELLIA_DECRYPT) { + camellia_setkey_dec(&ctx, key, 128 + u * 64); + } else { + camellia_setkey_enc(&ctx, key, 128 + u * 64); + } + + for (i = 0; i < CAMELLIA_TESTS_CBC; i++ ) { + + if (v == CAMELLIA_DECRYPT) { + memcpy( iv , src, 16 ); + memcpy(src, camellia_test_cbc_cipher[u][i], 16); + memcpy(dst, camellia_test_cbc_plain[i], 16); + } else { /* CAMELLIA_ENCRYPT */ + memcpy( iv , dst, 16 ); + memcpy(src, camellia_test_cbc_plain[i], 16); + memcpy(dst, camellia_test_cbc_cipher[u][i], 16); + } + + camellia_crypt_cbc(&ctx, v, 16, iv, src, buf); + + if( memcmp( buf, dst, 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + +#if defined(POLARSSL_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " CAMELLIA-CTR-128 (%s): ", + ( v == CAMELLIA_DECRYPT ) ? "dec" : "enc" ); + + memcpy( nonce_counter, camellia_test_ctr_nonce_counter[u], 16 ); + memcpy( key, camellia_test_ctr_key[u], 16 ); + + offset = 0; + camellia_setkey_enc( &ctx, key, 128 ); + + if( v == CAMELLIA_DECRYPT ) + { + len = camellia_test_ctr_len[u]; + memcpy( buf, camellia_test_ctr_ct[u], len ); + + camellia_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, buf, buf ); + + if( memcmp( buf, camellia_test_ctr_pt[u], len ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + else + { + len = camellia_test_ctr_len[u]; + memcpy( buf, camellia_test_ctr_pt[u], len ); + + camellia_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, buf, buf ); + + if( memcmp( buf, camellia_test_ctr_ct[u], len ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); +#endif /* POLARSSL_CIPHER_MODE_CTR */ + + return ( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/camellia.h b/src/libpolarssl/camellia.h new file mode 100644 index 0000000..050c6cd --- /dev/null +++ b/src/libpolarssl/camellia.h @@ -0,0 +1,200 @@ +/** + * \file camellia.h + * + * \brief Camellia block cipher + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_CAMELLIA_H +#define POLARSSL_CAMELLIA_H + +#include "config.h" + +#include + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define CAMELLIA_ENCRYPT 1 +#define CAMELLIA_DECRYPT 0 + +#define POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH -0x0024 /**< Invalid key length. */ +#define POLARSSL_ERR_CAMELLIA_INVALID_INPUT_LENGTH -0x0026 /**< Invalid data input length. */ + +#if !defined(POLARSSL_CAMELLIA_ALT) +// Regular implementation +// + +/** + * \brief CAMELLIA context structure + */ +typedef struct +{ + int nr; /*!< number of rounds */ + uint32_t rk[68]; /*!< CAMELLIA round keys */ +} +camellia_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CAMELLIA key schedule (encryption) + * + * \param ctx CAMELLIA context to be initialized + * \param key encryption key + * \param keysize must be 128, 192 or 256 + * + * \return 0 if successful, or POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH + */ +int camellia_setkey_enc( camellia_context *ctx, const unsigned char *key, unsigned int keysize ); + +/** + * \brief CAMELLIA key schedule (decryption) + * + * \param ctx CAMELLIA context to be initialized + * \param key decryption key + * \param keysize must be 128, 192 or 256 + * + * \return 0 if successful, or POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH + */ +int camellia_setkey_dec( camellia_context *ctx, const unsigned char *key, unsigned int keysize ); + +/** + * \brief CAMELLIA-ECB block encryption/decryption + * + * \param ctx CAMELLIA context + * \param mode CAMELLIA_ENCRYPT or CAMELLIA_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int camellia_crypt_ecb( camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief CAMELLIA-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \param ctx CAMELLIA context + * \param mode CAMELLIA_ENCRYPT or CAMELLIA_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or POLARSSL_ERR_CAMELLIA_INVALID_INPUT_LENGTH + */ +int camellia_crypt_cbc( camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief CAMELLIA-CFB128 buffer encryption/decryption + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * camellia_setkey_enc() for both CAMELLIA_ENCRYPT and CAMELLIE_DECRYPT. + * + * \param ctx CAMELLIA context + * \param mode CAMELLIA_ENCRYPT or CAMELLIA_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or POLARSSL_ERR_CAMELLIA_INVALID_INPUT_LENGTH + */ +int camellia_crypt_cfb128( camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief CAMELLIA-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * camellia_setkey_enc() for both CAMELLIA_ENCRYPT and CAMELLIA_DECRYPT. + * + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int camellia_crypt_ctr( camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_CAMELLIA_ALT */ +#include "camellia_alt.h" +#endif /* POLARSSL_CAMELLIA_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int camellia_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* camellia.h */ diff --git a/src/libpolarssl/certs.c b/src/libpolarssl/certs.c new file mode 100644 index 0000000..f35f8de --- /dev/null +++ b/src/libpolarssl/certs.c @@ -0,0 +1,196 @@ +/* + * X.509 test certificates + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_CERTS_C) + +const char test_ca_crt[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDhzCCAm+gAwIBAgIBADANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" +"MTEwMjEyMTQ0NDAwWhcNMjEwMjEyMTQ0NDAwWjA7MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G\r\n" +"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx\r\n" +"mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny\r\n" +"50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n\r\n" +"YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL\r\n" +"R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu\r\n" +"KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj\r\n" +"gZUwgZIwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUtFrkpbPe0lL2udWmlQ/rPrzH\r\n" +"/f8wYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNV\r\n" +"BAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVz\r\n" +"dCBDQYIBADANBgkqhkiG9w0BAQUFAAOCAQEAuP1U2ABUkIslsCfdlc2i94QHHYeJ\r\n" +"SsR4EdgHtdciUI5I62J6Mom+Y0dT/7a+8S6MVMCZP6C5NyNyXw1GWY/YR82XTJ8H\r\n" +"DBJiCTok5DbZ6SzaONBzdWHXwWwmi5vg1dxn7YxrM9d0IjxM27WNKs4sDQhZBQkF\r\n" +"pjmfs2cb4oPl4Y9T9meTx/lvdkRYEug61Jfn6cA+qHpyPYdTH+UshITnmp5/Ztkf\r\n" +"m/UTSLBNFNHesiTZeH31NcxYGdHSme9Nc/gfidRa0FLOCfWxRlFqAI47zG9jAQCZ\r\n" +"7Z2mCGDNMhjQc+BYcdnl0lPXjdDK6V0qCg1dVewhUBcW5gZKzV7e9+DpVA==\r\n" +"-----END CERTIFICATE-----\r\n"; + +const char test_ca_key[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"Proc-Type: 4,ENCRYPTED\r\n" +"DEK-Info: DES-EDE3-CBC,A8A95B05D5B7206B\r\n" +"\r\n" +"9Qd9GeArejl1GDVh2lLV1bHt0cPtfbh5h/5zVpAVaFpqtSPMrElp50Rntn9et+JA\r\n" +"7VOyboR+Iy2t/HU4WvA687k3Bppe9GwKHjHhtl//8xFKwZr3Xb5yO5JUP8AUctQq\r\n" +"Nb8CLlZyuUC+52REAAthdWgsX+7dJO4yabzUcQ22Tp9JSD0hiL43BlkWYUNK3dAo\r\n" +"PZlmiptjnzVTjg1MxsBSydZinWOLBV8/JQgxSPo2yD4uEfig28qbvQ2wNIn0pnAb\r\n" +"GxnSAOazkongEGfvcjIIs+LZN9gXFhxcOh6kc4Q/c99B7QWETwLLkYgZ+z1a9VY9\r\n" +"gEU7CwCxYCD+h9hY6FPmsK0/lC4O7aeRKpYq00rPPxs6i7phiexg6ax6yTMmArQq\r\n" +"QmK3TAsJm8V/J5AWpLEV6jAFgRGymGGHnof0DXzVWZidrcZJWTNuGEX90nB3ee2w\r\n" +"PXJEFWKoD3K3aFcSLdHYr3mLGxP7H9ThQai9VsycxZKS5kwvBKQ//YMrmFfwPk8x\r\n" +"vTeY4KZMaUrveEel5tWZC94RSMKgxR6cyE1nBXyTQnDOGbfpNNgBKxyKbINWoOJU\r\n" +"WJZAwlsQn+QzCDwpri7+sV1mS3gBE6UY7aQmnmiiaC2V3Hbphxct/en5QsfDOt1X\r\n" +"JczSfpRWLlbPznZg8OQh/VgCMA58N5DjOzTIK7sJJ5r+94ZBTCpgAMbF588f0NTR\r\n" +"KCe4yrxGJR7X02M4nvD4IwOlpsQ8xQxZtOSgXv4LkxvdU9XJJKWZ/XNKJeWztxSe\r\n" +"Z1vdTc2YfsDBA2SEv33vxHx2g1vqtw8SjDRT2RaQSS0QuSaMJimdOX6mTOCBKk1J\r\n" +"9Q5mXTrER+/LnK0jEmXsBXWA5bqqVZIyahXSx4VYZ7l7w/PHiUDtDgyRhMMKi4n2\r\n" +"iQvQcWSQTjrpnlJbca1/DkpRt3YwrvJwdqb8asZU2VrNETh5x0QVefDRLFiVpif/\r\n" +"tUaeAe/P1F8OkS7OIZDs1SUbv/sD2vMbhNkUoCms3/PvNtdnvgL4F0zhaDpKCmlT\r\n" +"P8vx49E7v5CyRNmED9zZg4o3wmMqrQO93PtTug3Eu9oVx1zPQM1NVMyBa2+f29DL\r\n" +"1nuTCeXdo9+ni45xx+jAI4DCwrRdhJ9uzZyC6962H37H6D+5naNvClFR1s6li1Gb\r\n" +"nqPoiy/OBsEx9CaDGcqQBp5Wme/3XW+6z1ISOx+igwNTVCT14mHdBMbya0eIKft5\r\n" +"X+GnwtgEMyCYyyWuUct8g4RzErcY9+yW9Om5Hzpx4zOuW4NPZgPDTgK+t2RSL/Yq\r\n" +"rE1njrgeGYcVeG3f+OftH4s6fPbq7t1A5ZgUscbLMBqr9tK+OqygR4EgKBPsH6Cz\r\n" +"L6zlv/2RV0qAHvVuDJcIDIgwY5rJtINEm32rhOeFNJwZS5MNIC1czXZx5//ugX7l\r\n" +"I4sy5nbVhwSjtAk8Xg5dZbdTZ6mIrb7xqH+fdakZor1khG7bC2uIwibD3cSl2XkR\r\n" +"wN48lslbHnqqagr6Xm1nNOSVl8C/6kbJEsMpLhAezfRtGwvOucoaE+WbeUNolGde\r\n" +"P/eQiddSf0brnpiLJRh7qZrl9XuqYdpUqnoEdMAfotDOID8OtV7gt8a48ad8VPW2\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; + +const char test_ca_pwd[] = "PolarSSLTest"; + +const char test_srv_crt[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDPzCCAiegAwIBAgIBATANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" +"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA8MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxGjAYBgNVBAMTEVBvbGFyU1NMIFNlcnZlciAxMIIBIjAN\r\n" +"BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQIfPUBq1VVTi/027oJlLhVhXom/\r\n" +"uOhFkNvuiBZS0/FDUEeWEllkh2v9K+BG+XO+3c+S4ZFb7Wagb4kpeUWA0INq1UFD\r\n" +"d185fAkER4KwVzlw7aPsFRkeqDMIR8EFQqn9TMO0390GH00QUUBncxMPQPhtgSVf\r\n" +"CrFTxjB+FTms+Vruf5KepgVb5xOXhbUjktnUJAbVCSWJdQfdphqPPwkZvq1lLGTr\r\n" +"lZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9w\r\n" +"bp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQAB\r\n" +"o00wSzAJBgNVHRMEAjAAMB0GA1UdDgQWBBQfdNY/KcF0dEU7BRIsPai9Q1kCpjAf\r\n" +"BgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zANBgkqhkiG9w0BAQUFAAOC\r\n" +"AQEAvc+WwZUemsJu2IiI2Cp6liA+UAvIx98dQe3kZs2zAoF9VwQbXcYzWQ/BILkj\r\n" +"NImKbPL9x0g2jIDn4ZvGYFywMwIO/d++YbwYiQw42/v7RiMy94zBPnzeHi86dy/0\r\n" +"jpOOJUx3IXRsGLdyjb/1T11klcFqGnARiK+8VYolMPP6afKvLXX7K4kiUpsFQhUp\r\n" +"E5VeM5pV1Mci2ETOJau2cO40FJvI/C9W/wR+GAArMaw2fxG77E3laaa0LAOlexM6\r\n" +"A4KOb5f5cGTM5Ih6tEF5FVq3/9vzNIYMa1FqzacBLZF8zSHYLEimXBdzjBoN4qDU\r\n" +"/WzRyYRBRjAI49mzHX6raleqnw==\r\n" +"-----END CERTIFICATE-----\r\n"; + +const char test_srv_key[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"MIIEogIBAAKCAQEAqQIfPUBq1VVTi/027oJlLhVhXom/uOhFkNvuiBZS0/FDUEeW\r\n" +"Ellkh2v9K+BG+XO+3c+S4ZFb7Wagb4kpeUWA0INq1UFDd185fAkER4KwVzlw7aPs\r\n" +"FRkeqDMIR8EFQqn9TMO0390GH00QUUBncxMPQPhtgSVfCrFTxjB+FTms+Vruf5Ke\r\n" +"pgVb5xOXhbUjktnUJAbVCSWJdQfdphqPPwkZvq1lLGTrlZvc/kFeF6babFtpzAK6\r\n" +"FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9wbp7OvViJ4lNZnm5akmXi\r\n" +"iD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQABAoIBABaJ9eiRQq4Ypv+w\r\n" +"UTcVpLC0oTueWzcpor1i1zjG4Vzqe/Ok2FqyGToGKMlFK7Hwwa+LEyeJ3xyV5yd4\r\n" +"v1Mw9bDZFdJC1eCBjoUAHtX6k9HOE0Vd6woVQ4Vi6OPI1g7B5Mnr/58rNrnN6TMs\r\n" +"x58NF6euecwTU811QJrZtLbX7j2Cr28yB2Vs8qyYlHwVw5jbDOv43D7vU5gmlIDN\r\n" +"0JQRuWAnOuPzZNoJr4SfJKqHNGxYYY6pHZ1s0dOTLIDb/B8KQWapA2kRmZyid2EH\r\n" +"nwzgLbAsHJCf+bQnhXjXuxtUsrcIL8noZLazlOMxwNEammglVWW23Ud/QRnFgJg5\r\n" +"UgcAcRECgYEA19uYetht5qmwdJ+12oC6zeO+vXLcyD9gon23T5J6w2YThld7/OW0\r\n" +"oArQJGgkAdaq0pcTyOIjtTQVMFygdVmCEJmxh/3RutPcTeydqW9fphKDMej32J8e\r\n" +"GniGmNGiclbcfNOS8E5TGp445yZb9P1+7AHng16bGg3Ykj5EA4G+HCcCgYEAyHAl\r\n" +"//ekk8YjQElm+8izLtFkymIK0aCtEe9C/RIRhFYBeFaotC5dStNhBOncn4ovMAPD\r\n" +"lX/92yDi9OP8PPLN3a4B9XpW3k/SS5GrbT5cwOivBHNllZSmu/2qz5WPGcjVCOrB\r\n" +"LYl3YWr2h3EGKICT03kEoTkiDBvCeOpW7cCGl2cCgYBD5whoXHz1+ptPlI4YVjZt\r\n" +"Xh86aU+ajpVPiEyJ84I6xXmO4SZXv8q6LaycR0ZMbcL+zBelMb4Z2nBv7jNrtuR7\r\n" +"ZF28cdPv+YVr3esaybZE/73VjXup4SQPH6r3l7qKTVi+y6+FeJ4b2Xn8/MwgnT23\r\n" +"8EFrye7wmzpthrjOgZnUMQKBgE9Lhsz/5J0Nis6Y+2Pqn3CLKEukg9Ewtqdct2y0\r\n" +"5Dcta0F3TyCRIxlCDKTL/BslqMtfAdY4H268UO0+8IAQMn9boqzBrHIgs/pvc5kx\r\n" +"TbKHmw2wtWR6vYersBKVgVpbCGSRssDYHGFu1n74qM4HJ/RGcR1zI9QUe1gopSFD\r\n" +"xDtLAoGAVAdWvrqDwgoL2hHW3scGpxdE/ygJDOwHnf+1B9goKAOP5lf2FJaiAxf3\r\n" +"ectoPOgZbCmm/iiDmigu703ld3O+VoCLDD4qx3R+KyALL78gtVJYzSRiKhzgCZ3g\r\n" +"mKsIVRBq4IfwiwyMNG2BYZQAwbSDjjPtn/kPBduPzPj7eriByhI=\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; + +const char test_cli_crt[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDPzCCAiegAwIBAgIBBDANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" +"MTEwMjEyMTQ0NDA3WhcNMjEwMjEyMTQ0NDA3WjA8MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxGjAYBgNVBAMTEVBvbGFyU1NMIENsaWVudCAyMIIBIjAN\r\n" +"BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6f\r\n" +"M60Nj4o8VmXl3ETZzGaFB9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu\r\n" +"1C93KYRhTYJQj6eVSHD1bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEw\r\n" +"MjDV0/YI0FZPRo7yX/k9Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v\r\n" +"4Jv4EFbMs44TFeY0BGbH7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx/\r\n" +"/DZrtenNLQNiTrM9AM+vdqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQAB\r\n" +"o00wSzAJBgNVHRMEAjAAMB0GA1UdDgQWBBRxoQBzckAvVHZeM/xSj7zx3WtGITAf\r\n" +"BgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zANBgkqhkiG9w0BAQUFAAOC\r\n" +"AQEAAn86isAM8X+mVwJqeItt6E9slhEQbAofyk+diH1Lh8Y9iLlWQSKbw/UXYjx5\r\n" +"LLPZcniovxIcARC/BjyZR9g3UwTHNGNm+rwrqa15viuNOFBchykX/Orsk02EH7NR\r\n" +"Alw5WLPorYjED6cdVQgBl9ot93HdJogRiXCxErM7NC8/eP511mjq+uLDjLKH8ZPQ\r\n" +"8I4ekHJnroLsDkIwXKGIsvIBHQy2ac/NwHLCQOK6mfum1pRx52V4Utu5dLLjD5bM\r\n" +"xOBC7KU4xZKuMXXZM6/93Yb51K/J4ahf1TxJlTWXtnzDr9saEYdNy2SKY/6ZiDNH\r\n" +"D+stpAKiQLAWaAusIWKYEyw9MQ==\r\n" +"-----END CERTIFICATE-----\r\n"; + +const char test_cli_key[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"MIIEpAIBAAKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6fM60Nj4o8VmXl3ETZzGaF\r\n" +"B9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu1C93KYRhTYJQj6eVSHD1\r\n" +"bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEwMjDV0/YI0FZPRo7yX/k9\r\n" +"Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v4Jv4EFbMs44TFeY0BGbH\r\n" +"7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx//DZrtenNLQNiTrM9AM+v\r\n" +"dqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQABAoIBAGdNtfYDiap6bzst\r\n" +"yhCiI8m9TtrhZw4MisaEaN/ll3XSjaOG2dvV6xMZCMV+5TeXDHOAZnY18Yi18vzz\r\n" +"4Ut2TnNFzizCECYNaA2fST3WgInnxUkV3YXAyP6CNxJaCmv2aA0yFr2kFVSeaKGt\r\n" +"ymvljNp2NVkvm7Th8fBQBO7I7AXhz43k0mR7XmPgewe8ApZOG3hstkOaMvbWAvWA\r\n" +"zCZupdDjZYjOJqlA4eEA4H8/w7F83r5CugeBE8LgEREjLPiyejrU5H1fubEY+h0d\r\n" +"l5HZBJ68ybTXfQ5U9o/QKA3dd0toBEhhdRUDGzWtjvwkEQfqF1reGWj/tod/gCpf\r\n" +"DFi6X0ECgYEA4wOv/pjSC3ty6TuOvKX2rOUiBrLXXv2JSxZnMoMiWI5ipLQt+RYT\r\n" +"VPafL/m7Dn6MbwjayOkcZhBwk5CNz5A6Q4lJ64Mq/lqHznRCQQ2Mc1G8eyDF/fYL\r\n" +"Ze2pLvwP9VD5jTc2miDfw+MnvJhywRRLcemDFP8k4hQVtm8PMp3ZmNECgYEA4gz7\r\n" +"wzObR4gn8ibe617uQPZjWzUj9dUHYd+in1gwBCIrtNnaRn9I9U/Q6tegRYpii4ys\r\n" +"c176NmU+umy6XmuSKV5qD9bSpZWG2nLFnslrN15Lm3fhZxoeMNhBaEDTnLT26yoi\r\n" +"33gp0mSSWy94ZEqipms+ULF6sY1ZtFW6tpGFoy8CgYAQHhnnvJflIs2ky4q10B60\r\n" +"ZcxFp3rtDpkp0JxhFLhiizFrujMtZSjYNm5U7KkgPVHhLELEUvCmOnKTt4ap/vZ0\r\n" +"BxJNe1GZH3pW6SAvGDQpl9sG7uu/vTFP+lCxukmzxB0DrrDcvorEkKMom7ZCCRvW\r\n" +"KZsZ6YeH2Z81BauRj218kQKBgQCUV/DgKP2985xDTT79N08jUo3hTP5MVYCCuj/+\r\n" +"UeEw1TvZcx3LJby7P6Xad6a1/BqveaGyFKIfEFIaBUBItk801sDDpDaYc4gL00Xc\r\n" +"7lFuBHOZkxJYlss5QrGpuOEl9ZwUt5IrFLBdYaKqNHzNVC1pCPfb/JyH6Dr2HUxq\r\n" +"gxUwAQKBgQCcU6G2L8AG9d9c0UpOyL1tMvFe5Ttw0KjlQVdsh1MP6yigYo9DYuwu\r\n" +"bHFVW2r0dBTqegP2/KTOxKzaHfC1qf0RGDsUoJCNJrd1cwoCLG8P2EF4w3OBrKqv\r\n" +"8u4ytY0F+Vlanj5lm3TaoHSVF1+NWPyOTiwevIECGKwSxvlki4fDAA==\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; + +const char test_dhm_params[] = +"-----BEGIN DH PARAMETERS-----\r\n" +"MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n" +"1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n" +"9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n" +"-----END DH PARAMETERS-----\r\n"; + +#endif diff --git a/src/libpolarssl/certs.h b/src/libpolarssl/certs.h new file mode 100644 index 0000000..5399e32 --- /dev/null +++ b/src/libpolarssl/certs.h @@ -0,0 +1,47 @@ +/** + * \file certs.h + * + * \brief Sample certificates and DHM parameters for testing + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_CERTS_H +#define POLARSSL_CERTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char test_ca_crt[]; +extern const char test_ca_key[]; +extern const char test_ca_pwd[]; +extern const char test_srv_crt[]; +extern const char test_srv_key[]; +extern const char test_cli_crt[]; +extern const char test_cli_key[]; +extern const char test_dhm_params[]; + +#ifdef __cplusplus +} +#endif + +#endif /* certs.h */ diff --git a/src/libpolarssl/cipher.c b/src/libpolarssl/cipher.c new file mode 100644 index 0000000..b134be3 --- /dev/null +++ b/src/libpolarssl/cipher.c @@ -0,0 +1,601 @@ +/** + * \file cipher.c + * + * \brief Generic cipher wrapper for PolarSSL + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_CIPHER_C) + +#include "cipher.h" +#include "cipher_wrap.h" + +#include + +#if defined _MSC_VER && !defined strcasecmp +#define strcasecmp _stricmp +#endif + +static const int supported_ciphers[] = { + +#if defined(POLARSSL_AES_C) + POLARSSL_CIPHER_AES_128_CBC, + POLARSSL_CIPHER_AES_192_CBC, + POLARSSL_CIPHER_AES_256_CBC, + +#if defined(POLARSSL_CIPHER_MODE_CFB) + POLARSSL_CIPHER_AES_128_CFB128, + POLARSSL_CIPHER_AES_192_CFB128, + POLARSSL_CIPHER_AES_256_CFB128, +#endif /* defined(POLARSSL_CIPHER_MODE_CFB) */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) + POLARSSL_CIPHER_AES_128_CTR, + POLARSSL_CIPHER_AES_192_CTR, + POLARSSL_CIPHER_AES_256_CTR, +#endif /* defined(POLARSSL_CIPHER_MODE_CTR) */ + +#endif /* defined(POLARSSL_AES_C) */ + +#if defined(POLARSSL_CAMELLIA_C) + POLARSSL_CIPHER_CAMELLIA_128_CBC, + POLARSSL_CIPHER_CAMELLIA_192_CBC, + POLARSSL_CIPHER_CAMELLIA_256_CBC, + +#if defined(POLARSSL_CIPHER_MODE_CFB) + POLARSSL_CIPHER_CAMELLIA_128_CFB128, + POLARSSL_CIPHER_CAMELLIA_192_CFB128, + POLARSSL_CIPHER_CAMELLIA_256_CFB128, +#endif /* defined(POLARSSL_CIPHER_MODE_CFB) */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) + POLARSSL_CIPHER_CAMELLIA_128_CTR, + POLARSSL_CIPHER_CAMELLIA_192_CTR, + POLARSSL_CIPHER_CAMELLIA_256_CTR, +#endif /* defined(POLARSSL_CIPHER_MODE_CTR) */ + +#endif /* defined(POLARSSL_CAMELLIA_C) */ + +#if defined(POLARSSL_DES_C) + POLARSSL_CIPHER_DES_CBC, + POLARSSL_CIPHER_DES_EDE_CBC, + POLARSSL_CIPHER_DES_EDE3_CBC, +#endif /* defined(POLARSSL_DES_C) */ + +#if defined(POLARSSL_BLOWFISH_C) + POLARSSL_CIPHER_BLOWFISH_CBC, + +#if defined(POLARSSL_CIPHER_MODE_CFB) + POLARSSL_CIPHER_BLOWFISH_CFB64, +#endif /* defined(POLARSSL_CIPHER_MODE_CFB) */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) + POLARSSL_CIPHER_BLOWFISH_CTR, +#endif /* defined(POLARSSL_CIPHER_MODE_CTR) */ + +#endif /* defined(POLARSSL_BLOWFISH_C) */ + +#if defined(POLARSSL_CIPHER_NULL_CIPHER) + POLARSSL_CIPHER_NULL, +#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ + + 0 +}; + +const int *cipher_list( void ) +{ + return supported_ciphers; +} + +const cipher_info_t *cipher_info_from_type( const cipher_type_t cipher_type ) +{ + /* Find static cipher information */ + switch ( cipher_type ) + { +#if defined(POLARSSL_AES_C) + case POLARSSL_CIPHER_AES_128_CBC: + return &aes_128_cbc_info; + case POLARSSL_CIPHER_AES_192_CBC: + return &aes_192_cbc_info; + case POLARSSL_CIPHER_AES_256_CBC: + return &aes_256_cbc_info; + +#if defined(POLARSSL_CIPHER_MODE_CFB) + case POLARSSL_CIPHER_AES_128_CFB128: + return &aes_128_cfb128_info; + case POLARSSL_CIPHER_AES_192_CFB128: + return &aes_192_cfb128_info; + case POLARSSL_CIPHER_AES_256_CFB128: + return &aes_256_cfb128_info; +#endif /* defined(POLARSSL_CIPHER_MODE_CFB) */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) + case POLARSSL_CIPHER_AES_128_CTR: + return &aes_128_ctr_info; + case POLARSSL_CIPHER_AES_192_CTR: + return &aes_192_ctr_info; + case POLARSSL_CIPHER_AES_256_CTR: + return &aes_256_ctr_info; +#endif /* defined(POLARSSL_CIPHER_MODE_CTR) */ + +#endif + +#if defined(POLARSSL_CAMELLIA_C) + case POLARSSL_CIPHER_CAMELLIA_128_CBC: + return &camellia_128_cbc_info; + case POLARSSL_CIPHER_CAMELLIA_192_CBC: + return &camellia_192_cbc_info; + case POLARSSL_CIPHER_CAMELLIA_256_CBC: + return &camellia_256_cbc_info; + +#if defined(POLARSSL_CIPHER_MODE_CFB) + case POLARSSL_CIPHER_CAMELLIA_128_CFB128: + return &camellia_128_cfb128_info; + case POLARSSL_CIPHER_CAMELLIA_192_CFB128: + return &camellia_192_cfb128_info; + case POLARSSL_CIPHER_CAMELLIA_256_CFB128: + return &camellia_256_cfb128_info; +#endif /* defined(POLARSSL_CIPHER_MODE_CFB) */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) + case POLARSSL_CIPHER_CAMELLIA_128_CTR: + return &camellia_128_ctr_info; + case POLARSSL_CIPHER_CAMELLIA_192_CTR: + return &camellia_192_ctr_info; + case POLARSSL_CIPHER_CAMELLIA_256_CTR: + return &camellia_256_ctr_info; +#endif /* defined(POLARSSL_CIPHER_MODE_CTR) */ + +#endif + +#if defined(POLARSSL_DES_C) + case POLARSSL_CIPHER_DES_CBC: + return &des_cbc_info; + case POLARSSL_CIPHER_DES_EDE_CBC: + return &des_ede_cbc_info; + case POLARSSL_CIPHER_DES_EDE3_CBC: + return &des_ede3_cbc_info; +#endif + +#if defined(POLARSSL_BLOWFISH_C) + case POLARSSL_CIPHER_BLOWFISH_CBC: + return &blowfish_cbc_info; + +#if defined(POLARSSL_CIPHER_MODE_CFB) + case POLARSSL_CIPHER_BLOWFISH_CFB64: + return &blowfish_cfb64_info; +#endif /* defined(POLARSSL_CIPHER_MODE_CFB) */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) + case POLARSSL_CIPHER_BLOWFISH_CTR: + return &blowfish_ctr_info; +#endif /* defined(POLARSSL_CIPHER_MODE_CTR) */ + +#endif + +#if defined(POLARSSL_CIPHER_NULL_CIPHER) + case POLARSSL_CIPHER_NULL: + return &null_cipher_info; +#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ + + default: + return NULL; + } +} + +const cipher_info_t *cipher_info_from_string( const char *cipher_name ) +{ + if( NULL == cipher_name ) + return NULL; + + /* Get the appropriate cipher information */ +#if defined(POLARSSL_CAMELLIA_C) + if( !strcasecmp( "CAMELLIA-128-CBC", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_CAMELLIA_128_CBC ); + if( !strcasecmp( "CAMELLIA-192-CBC", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_CAMELLIA_192_CBC ); + if( !strcasecmp( "CAMELLIA-256-CBC", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_CAMELLIA_256_CBC ); + +#if defined(POLARSSL_CIPHER_MODE_CFB) + if( !strcasecmp( "CAMELLIA-128-CFB128", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_CAMELLIA_128_CFB128 ); + if( !strcasecmp( "CAMELLIA-192-CFB128", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_CAMELLIA_192_CFB128 ); + if( !strcasecmp( "CAMELLIA-256-CFB128", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_CAMELLIA_256_CFB128 ); +#endif /* defined(POLARSSL_CIPHER_MODE_CFB) */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) + if( !strcasecmp( "CAMELLIA-128-CTR", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_CAMELLIA_128_CTR ); + if( !strcasecmp( "CAMELLIA-192-CTR", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_CAMELLIA_192_CTR ); + if( !strcasecmp( "CAMELLIA-256-CTR", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_CAMELLIA_256_CTR ); +#endif /* defined(POLARSSL_CIPHER_MODE_CTR) */ +#endif + +#if defined(POLARSSL_AES_C) + if( !strcasecmp( "AES-128-CBC", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_AES_128_CBC ); + if( !strcasecmp( "AES-192-CBC", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_AES_192_CBC ); + if( !strcasecmp( "AES-256-CBC", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_AES_256_CBC ); + +#if defined(POLARSSL_CIPHER_MODE_CFB) + if( !strcasecmp( "AES-128-CFB128", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_AES_128_CFB128 ); + if( !strcasecmp( "AES-192-CFB128", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_AES_192_CFB128 ); + if( !strcasecmp( "AES-256-CFB128", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_AES_256_CFB128 ); +#endif /* defined(POLARSSL_CIPHER_MODE_CFB) */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) + if( !strcasecmp( "AES-128-CTR", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_AES_128_CTR ); + if( !strcasecmp( "AES-192-CTR", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_AES_192_CTR ); + if( !strcasecmp( "AES-256-CTR", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_AES_256_CTR ); +#endif /* defined(POLARSSL_CIPHER_MODE_CTR) */ +#endif + +#if defined(POLARSSL_DES_C) + if( !strcasecmp( "DES-CBC", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_DES_CBC ); + if( !strcasecmp( "DES-EDE-CBC", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_DES_EDE_CBC ); + if( !strcasecmp( "DES-EDE3-CBC", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_DES_EDE3_CBC ); +#endif + +#if defined(POLARSSL_BLOWFISH_C) + if( !strcasecmp( "BLOWFISH-CBC", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_BLOWFISH_CBC ); + +#if defined(POLARSSL_CIPHER_MODE_CFB) + if( !strcasecmp( "BLOWFISH-CFB64", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_BLOWFISH_CFB64 ); +#endif /* defined(POLARSSL_CIPHER_MODE_CFB) */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) + if( !strcasecmp( "BLOWFISH-CTR", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_BLOWFISH_CTR ); +#endif /* defined(POLARSSL_CIPHER_MODE_CTR) */ +#endif + +#if defined(POLARSSL_CIPHER_NULL_CIPHER) + if( !strcasecmp( "NULL", cipher_name ) ) + return cipher_info_from_type( POLARSSL_CIPHER_NULL ); +#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ + + return NULL; +} + +int cipher_init_ctx( cipher_context_t *ctx, const cipher_info_t *cipher_info ) +{ + if( NULL == cipher_info || NULL == ctx ) + return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; + + memset( ctx, 0, sizeof( cipher_context_t ) ); + + if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) ) + return POLARSSL_ERR_CIPHER_ALLOC_FAILED; + + ctx->cipher_info = cipher_info; + + return 0; +} + +int cipher_free_ctx( cipher_context_t *ctx ) +{ + if( ctx == NULL || ctx->cipher_info == NULL ) + return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; + + ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx ); + + return 0; +} + +int cipher_setkey( cipher_context_t *ctx, const unsigned char *key, + int key_length, const operation_t operation ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; + + ctx->key_length = key_length; + ctx->operation = operation; + +#if defined(POLARSSL_CIPHER_NULL_CIPHER) + if( ctx->cipher_info->mode == POLARSSL_MODE_NULL ) + return 0; +#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ + + /* + * For CFB and CTR mode always use the encryption key schedule + */ + if( POLARSSL_ENCRYPT == operation || + POLARSSL_MODE_CFB == ctx->cipher_info->mode || + POLARSSL_MODE_CTR == ctx->cipher_info->mode ) + { + return ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key, + ctx->key_length ); + } + + if( POLARSSL_DECRYPT == operation ) + return ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key, + ctx->key_length ); + + return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; +} + +int cipher_reset( cipher_context_t *ctx, const unsigned char *iv ) +{ + if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv ) + return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; + + ctx->unprocessed_len = 0; + + memcpy( ctx->iv, iv, cipher_get_iv_size( ctx ) ); + + return 0; +} + +int cipher_update( cipher_context_t *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen ) +{ + int ret; + size_t copy_len = 0; + + if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen || + input == output ) + { + return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; + } + + *olen = 0; + +#if defined(POLARSSL_CIPHER_NULL_CIPHER) + if( ctx->cipher_info->mode == POLARSSL_MODE_NULL ) + { + memcpy( output, input, ilen ); + *olen = ilen; + return 0; + } +#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ + + if( ctx->cipher_info->mode == POLARSSL_MODE_CBC ) + { + /* + * If there is not enough data for a full block, cache it. + */ + if( ( ctx->operation == POLARSSL_DECRYPT && + ilen + ctx->unprocessed_len <= cipher_get_block_size( ctx ) ) || + ( ctx->operation == POLARSSL_ENCRYPT && + ilen + ctx->unprocessed_len < cipher_get_block_size( ctx ) ) ) + { + memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, + ilen ); + + ctx->unprocessed_len += ilen; + return 0; + } + + /* + * Process cached data first + */ + if( ctx->unprocessed_len != 0 ) + { + copy_len = cipher_get_block_size( ctx ) - ctx->unprocessed_len; + + memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, + copy_len ); + + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, cipher_get_block_size( ctx ), ctx->iv, + ctx->unprocessed_data, output ) ) ) + { + return ret; + } + + *olen += cipher_get_block_size( ctx ); + output += cipher_get_block_size( ctx ); + ctx->unprocessed_len = 0; + + input += copy_len; + ilen -= copy_len; + } + + /* + * Cache final, incomplete block + */ + if( 0 != ilen ) + { + copy_len = ilen % cipher_get_block_size( ctx ); + if( copy_len == 0 && ctx->operation == POLARSSL_DECRYPT ) + copy_len = cipher_get_block_size(ctx); + + memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ), + copy_len ); + + ctx->unprocessed_len += copy_len; + ilen -= copy_len; + } + + /* + * Process remaining full blocks + */ + if( ilen ) + { + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, ilen, ctx->iv, input, output ) ) ) + { + return ret; + } + *olen += ilen; + } + + return 0; + } + + if( ctx->cipher_info->mode == POLARSSL_MODE_CFB ) + { + if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx, + ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv, + input, output ) ) ) + { + return ret; + } + + *olen = ilen; + + return 0; + } + + if( ctx->cipher_info->mode == POLARSSL_MODE_CTR ) + { + if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx, + ilen, &ctx->unprocessed_len, ctx->iv, + ctx->unprocessed_data, input, output ) ) ) + { + return ret; + } + + *olen = ilen; + + return 0; + } + + return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE; +} + +static void add_pkcs_padding( unsigned char *output, size_t output_len, + size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i = 0; + + for( i = 0; i < padding_len; i++ ) + output[data_len + i] = (unsigned char) padding_len; +} + +static int get_pkcs_padding( unsigned char *input, unsigned int input_len, + size_t *data_len) +{ + unsigned int i, padding_len = 0; + + if( NULL == input || NULL == data_len ) + return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; + + padding_len = input[input_len - 1]; + + if( padding_len > input_len ) + return POLARSSL_ERR_CIPHER_INVALID_PADDING; + + for( i = input_len - padding_len; i < input_len; i++ ) + if( input[i] != padding_len ) + return POLARSSL_ERR_CIPHER_INVALID_PADDING; + + *data_len = input_len - padding_len; + + return 0; +} + +int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen) +{ + int ret = 0; + + if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) + return POLARSSL_ERR_CIPHER_BAD_INPUT_DATA; + + *olen = 0; + + if( POLARSSL_MODE_CFB == ctx->cipher_info->mode || + POLARSSL_MODE_CTR == ctx->cipher_info->mode || + POLARSSL_MODE_NULL == ctx->cipher_info->mode ) + { + return 0; + } + + if( POLARSSL_MODE_CBC == ctx->cipher_info->mode ) + { + if( POLARSSL_ENCRYPT == ctx->operation ) + { + add_pkcs_padding( ctx->unprocessed_data, cipher_get_iv_size( ctx ), + ctx->unprocessed_len ); + } + else if ( cipher_get_block_size( ctx ) != ctx->unprocessed_len ) + { + /* For decrypt operations, expect a full block */ + return POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED; + } + + /* cipher block */ + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, cipher_get_block_size( ctx ), ctx->iv, + ctx->unprocessed_data, output ) ) ) + { + return ret; + } + + /* Set output size for decryption */ + if( POLARSSL_DECRYPT == ctx->operation ) + return get_pkcs_padding( output, cipher_get_block_size( ctx ), olen ); + + /* Set output size for encryption */ + *olen = cipher_get_block_size( ctx ); + return 0; + } + + return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE; +} + +#if defined(POLARSSL_SELF_TEST) + +#include + +#define ASSERT(x) if (!(x)) { \ + printf( "failed with %i at %s\n", value, (#x) ); \ + return( 1 ); \ +} +/* + * Checkup routine + */ + +int cipher_self_test( int verbose ) +{ + ((void) verbose); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/cipher.h b/src/libpolarssl/cipher.h new file mode 100644 index 0000000..8224128 --- /dev/null +++ b/src/libpolarssl/cipher.h @@ -0,0 +1,463 @@ +/** + * \file cipher.h + * + * \brief Generic cipher wrapper. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef POLARSSL_CIPHER_H +#define POLARSSL_CIPHER_H + +#include + +#if defined(_MSC_VER) && !defined(inline) +#define inline _inline +#else +#if defined(__ARMCC_VERSION) && !defined(inline) +#define inline __inline +#endif /* __ARMCC_VERSION */ +#endif /*_MSC_VER */ + +#define POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE -0x6080 /**< The selected feature is not available. */ +#define POLARSSL_ERR_CIPHER_BAD_INPUT_DATA -0x6100 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_CIPHER_ALLOC_FAILED -0x6180 /**< Failed to allocate memory. */ +#define POLARSSL_ERR_CIPHER_INVALID_PADDING -0x6200 /**< Input data contains invalid padding and is rejected. */ +#define POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED -0x6280 /**< Decryption of block requires a full block. */ + +typedef enum { + POLARSSL_CIPHER_ID_NONE = 0, + POLARSSL_CIPHER_ID_NULL, + POLARSSL_CIPHER_ID_AES, + POLARSSL_CIPHER_ID_DES, + POLARSSL_CIPHER_ID_3DES, + POLARSSL_CIPHER_ID_CAMELLIA, + POLARSSL_CIPHER_ID_BLOWFISH, +} cipher_id_t; + +typedef enum { + POLARSSL_CIPHER_NONE = 0, + POLARSSL_CIPHER_NULL, + POLARSSL_CIPHER_AES_128_CBC, + POLARSSL_CIPHER_AES_192_CBC, + POLARSSL_CIPHER_AES_256_CBC, + POLARSSL_CIPHER_AES_128_CFB128, + POLARSSL_CIPHER_AES_192_CFB128, + POLARSSL_CIPHER_AES_256_CFB128, + POLARSSL_CIPHER_AES_128_CTR, + POLARSSL_CIPHER_AES_192_CTR, + POLARSSL_CIPHER_AES_256_CTR, + POLARSSL_CIPHER_CAMELLIA_128_CBC, + POLARSSL_CIPHER_CAMELLIA_192_CBC, + POLARSSL_CIPHER_CAMELLIA_256_CBC, + POLARSSL_CIPHER_CAMELLIA_128_CFB128, + POLARSSL_CIPHER_CAMELLIA_192_CFB128, + POLARSSL_CIPHER_CAMELLIA_256_CFB128, + POLARSSL_CIPHER_CAMELLIA_128_CTR, + POLARSSL_CIPHER_CAMELLIA_192_CTR, + POLARSSL_CIPHER_CAMELLIA_256_CTR, + POLARSSL_CIPHER_DES_CBC, + POLARSSL_CIPHER_DES_EDE_CBC, + POLARSSL_CIPHER_DES_EDE3_CBC, + POLARSSL_CIPHER_BLOWFISH_CBC, + POLARSSL_CIPHER_BLOWFISH_CFB64, + POLARSSL_CIPHER_BLOWFISH_CTR, +} cipher_type_t; + +typedef enum { + POLARSSL_MODE_NONE = 0, + POLARSSL_MODE_NULL, + POLARSSL_MODE_CBC, + POLARSSL_MODE_CFB, + POLARSSL_MODE_OFB, + POLARSSL_MODE_CTR, +} cipher_mode_t; + +typedef enum { + POLARSSL_OPERATION_NONE = -1, + POLARSSL_DECRYPT = 0, + POLARSSL_ENCRYPT, +} operation_t; + +enum { + /** Undefined key length */ + POLARSSL_KEY_LENGTH_NONE = 0, + /** Key length, in bits (including parity), for DES keys */ + POLARSSL_KEY_LENGTH_DES = 64, + /** Key length, in bits (including parity), for DES in two key EDE */ + POLARSSL_KEY_LENGTH_DES_EDE = 128, + /** Key length, in bits (including parity), for DES in three-key EDE */ + POLARSSL_KEY_LENGTH_DES_EDE3 = 192, + /** Maximum length of any IV, in bytes */ + POLARSSL_MAX_IV_LENGTH = 16, +}; + +/** + * Base cipher information. The non-mode specific functions and values. + */ +typedef struct { + + /** Base Cipher type (e.g. POLARSSL_CIPHER_ID_AES) */ + cipher_id_t cipher; + + /** Encrypt using CBC */ + int (*cbc_func)( void *ctx, operation_t mode, size_t length, unsigned char *iv, + const unsigned char *input, unsigned char *output ); + + /** Encrypt using CFB (Full length) */ + int (*cfb_func)( void *ctx, operation_t mode, size_t length, size_t *iv_off, + unsigned char *iv, const unsigned char *input, unsigned char *output ); + + /** Encrypt using CTR */ + int (*ctr_func)( void *ctx, size_t length, size_t *nc_off, unsigned char *nonce_counter, + unsigned char *stream_block, const unsigned char *input, unsigned char *output ); + + /** Set key for encryption purposes */ + int (*setkey_enc_func)( void *ctx, const unsigned char *key, unsigned int key_length); + + /** Set key for decryption purposes */ + int (*setkey_dec_func)( void *ctx, const unsigned char *key, unsigned int key_length); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + +} cipher_base_t; + +/** + * Cipher information. Allows cipher functions to be called in a generic way. + */ +typedef struct { + /** Full cipher identifier (e.g. POLARSSL_CIPHER_AES_256_CBC) */ + cipher_type_t type; + + /** Cipher mode (e.g. POLARSSL_MODE_CBC) */ + cipher_mode_t mode; + + /** Cipher key length, in bits (default length for variable sized ciphers) + * (Includes parity bits for ciphers like DES) */ + unsigned int key_length; + + /** Name of the cipher */ + const char * name; + + /** IV size, in bytes */ + unsigned int iv_size; + + /** block size, in bytes */ + unsigned int block_size; + + /** Base cipher information and functions */ + const cipher_base_t *base; + +} cipher_info_t; + +/** + * Generic cipher context. + */ +typedef struct { + /** Information about the associated cipher */ + const cipher_info_t *cipher_info; + + /** Key length to use */ + int key_length; + + /** Operation that the context's key has been initialised for */ + operation_t operation; + + /** Buffer for data that hasn't been encrypted yet */ + unsigned char unprocessed_data[POLARSSL_MAX_IV_LENGTH]; + + /** Number of bytes that still need processing */ + size_t unprocessed_len; + + /** Current IV or NONCE_COUNTER for CTR-mode */ + unsigned char iv[POLARSSL_MAX_IV_LENGTH]; + + /** Cipher-specific context */ + void *cipher_ctx; +} cipher_context_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Returns the list of ciphers supported by the generic cipher module. + * + * \return a statically allocated array of ciphers, the last entry + * is 0. + */ +const int *cipher_list( void ); + +/** + * \brief Returns the cipher information structure associated + * with the given cipher name. + * + * \param cipher_name Name of the cipher to search for. + * + * \return the cipher information structure associated with the + * given cipher_name, or NULL if not found. + */ +const cipher_info_t *cipher_info_from_string( const char *cipher_name ); + +/** + * \brief Returns the cipher information structure associated + * with the given cipher type. + * + * \param cipher_type Type of the cipher to search for. + * + * \return the cipher information structure associated with the + * given cipher_type, or NULL if not found. + */ +const cipher_info_t *cipher_info_from_type( const cipher_type_t cipher_type ); + +/** + * \brief Initialises and fills the cipher context structure with + * the appropriate values. + * + * \param ctx context to initialise. May not be NULL. + * \param cipher_info cipher to use. + * + * \return \c 0 on success, + * \c POLARSSL_ERR_CIPHER_BAD_INPUT_DATA on parameter failure, + * \c POLARSSL_ERR_CIPHER_ALLOC_FAILED if allocation of the + * cipher-specific context failed. + */ +int cipher_init_ctx( cipher_context_t *ctx, const cipher_info_t *cipher_info ); + +/** + * \brief Free the cipher-specific context of ctx. Freeing ctx + * itself remains the responsibility of the caller. + * + * \param ctx Free the cipher-specific context + * + * \returns 0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails. + */ +int cipher_free_ctx( cipher_context_t *ctx ); + +/** + * \brief Returns the block size of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return size of the cipher's blocks, or 0 if ctx has not been + * initialised. + */ +static inline unsigned int cipher_get_block_size( const cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->block_size; +} + +/** + * \brief Returns the mode of operation for the cipher. + * (e.g. POLARSSL_MODE_CBC) + * + * \param ctx cipher's context. Must have been initialised. + * + * \return mode of operation, or POLARSSL_MODE_NONE if ctx + * has not been initialised. + */ +static inline cipher_mode_t cipher_get_cipher_mode( const cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return POLARSSL_MODE_NONE; + + return ctx->cipher_info->mode; +} + +/** + * \brief Returns the size of the cipher's IV. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return size of the cipher's IV, or 0 if ctx has not been + * initialised. + */ +static inline int cipher_get_iv_size( const cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->iv_size; +} + +/** + * \brief Returns the type of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return type of the cipher, or POLARSSL_CIPHER_NONE if ctx has + * not been initialised. + */ +static inline cipher_type_t cipher_get_type( const cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return POLARSSL_CIPHER_NONE; + + return ctx->cipher_info->type; +} + +/** + * \brief Returns the name of the given cipher, as a string. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return name of the cipher, or NULL if ctx was not initialised. + */ +static inline const char *cipher_get_name( const cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->name; +} + +/** + * \brief Returns the key length of the cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return cipher's key length, in bits, or + * POLARSSL_KEY_LENGTH_NONE if ctx has not been + * initialised. + */ +static inline int cipher_get_key_size ( const cipher_context_t *ctx ) +{ + if( NULL == ctx ) + return POLARSSL_KEY_LENGTH_NONE; + + return ctx->key_length; +} + +/** + * \brief Returns the operation of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return operation (POLARSSL_ENCRYPT or POLARSSL_DECRYPT), + * or POLARSSL_OPERATION_NONE if ctx has not been + * initialised. + */ +static inline operation_t cipher_get_operation( const cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return POLARSSL_OPERATION_NONE; + + return ctx->operation; +} + +/** + * \brief Set the key to use with the given context. + * + * \param ctx generic cipher context. May not be NULL. Must have been + * initialised using cipher_context_from_type or + * cipher_context_from_string. + * \param key The key to use. + * \param key_length key length to use, in bits. + * \param operation Operation that the key will be used for, either + * POLARSSL_ENCRYPT or POLARSSL_DECRYPT. + * + * \returns 0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails or a cipher specific + * error code. + */ +int cipher_setkey( cipher_context_t *ctx, const unsigned char *key, int key_length, + const operation_t operation ); + +/** + * \brief Reset the given context, setting the IV to iv + * + * \param ctx generic cipher context + * \param iv IV to use or NONCE_COUNTER in the case of a CTR-mode cipher + * + * \returns 0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA + * if parameter verification fails. + */ +int cipher_reset( cipher_context_t *ctx, const unsigned char *iv ); + +/** + * \brief Generic cipher update function. Encrypts/decrypts + * using the given cipher context. Writes as many block + * size'd blocks of data as possible to output. Any data + * that cannot be written immediately will either be added + * to the next block, or flushed when cipher_final is + * called. + * + * \param ctx generic cipher context + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. Should be able to hold at + * least ilen + block_size. Cannot be the same buffer as + * input! + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * + * \returns 0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails, + * POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE on an + * unsupported mode for a cipher or a cipher specific + * error code. + */ +int cipher_update( cipher_context_t *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen ); + +/** + * \brief Generic cipher finalisation function. If data still + * needs to be flushed from an incomplete block, data + * contained within it will be padded with the size of + * the last block, and written to the output buffer. + * + * \param ctx Generic cipher context + * \param output buffer to write data to. Needs block_size data available. + * \param olen length of the data written to the output buffer. + * + * \returns 0 on success, POLARSSL_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails, + * POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption + * expected a full block but was not provided one, + * POLARSSL_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting or a cipher specific error code. + */ +int cipher_finish( cipher_context_t *ctx, unsigned char *output, size_t *olen); + + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int cipher_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* POLARSSL_MD_H */ diff --git a/src/libpolarssl/cipher_wrap.c b/src/libpolarssl/cipher_wrap.c new file mode 100644 index 0000000..4e85c88 --- /dev/null +++ b/src/libpolarssl/cipher_wrap.c @@ -0,0 +1,711 @@ +/** + * \file md_wrap.c + * + * \brief Generic cipher wrapper for PolarSSL + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_CIPHER_C) + +#include "cipher_wrap.h" + +#if defined(POLARSSL_AES_C) +#include "aes.h" +#endif + +#if defined(POLARSSL_CAMELLIA_C) +#include "camellia.h" +#endif + +#if defined(POLARSSL_DES_C) +#include "des.h" +#endif + +#if defined(POLARSSL_BLOWFISH_C) +#include "blowfish.h" +#endif + +#include + +#if defined(POLARSSL_AES_C) + +int aes_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return aes_crypt_cbc( (aes_context *) ctx, operation, length, iv, input, output ); +} + +int aes_crypt_cfb128_wrap( void *ctx, operation_t operation, size_t length, + size_t *iv_off, unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ +#if defined(POLARSSL_CIPHER_MODE_CFB) + return aes_crypt_cfb128( (aes_context *) ctx, operation, length, iv_off, iv, input, output ); +#else + ((void) ctx); + ((void) operation); + ((void) length); + ((void) iv_off); + ((void) iv); + ((void) input); + ((void) output); + + return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE; +#endif +} + +int aes_crypt_ctr_wrap( void *ctx, size_t length, + size_t *nc_off, unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ +#if defined(POLARSSL_CIPHER_MODE_CTR) + return aes_crypt_ctr( (aes_context *) ctx, length, nc_off, nonce_counter, + stream_block, input, output ); +#else + ((void) ctx); + ((void) length); + ((void) nc_off); + ((void) nonce_counter); + ((void) stream_block); + ((void) input); + ((void) output); + + return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE; +#endif +} + +int aes_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + return aes_setkey_dec( (aes_context *) ctx, key, key_length ); +} + +int aes_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + return aes_setkey_enc( (aes_context *) ctx, key, key_length ); +} + +static void * aes_ctx_alloc( void ) +{ + return malloc( sizeof( aes_context ) ); +} + +static void aes_ctx_free( void *ctx ) +{ + free( ctx ); +} + +const cipher_base_t aes_info = { + POLARSSL_CIPHER_ID_AES, + aes_crypt_cbc_wrap, + aes_crypt_cfb128_wrap, + aes_crypt_ctr_wrap, + aes_setkey_enc_wrap, + aes_setkey_dec_wrap, + aes_ctx_alloc, + aes_ctx_free +}; + +const cipher_info_t aes_128_cbc_info = { + POLARSSL_CIPHER_AES_128_CBC, + POLARSSL_MODE_CBC, + 128, + "AES-128-CBC", + 16, + 16, + &aes_info +}; + +const cipher_info_t aes_192_cbc_info = { + POLARSSL_CIPHER_AES_192_CBC, + POLARSSL_MODE_CBC, + 192, + "AES-192-CBC", + 16, + 16, + &aes_info +}; + +const cipher_info_t aes_256_cbc_info = { + POLARSSL_CIPHER_AES_256_CBC, + POLARSSL_MODE_CBC, + 256, + "AES-256-CBC", + 16, + 16, + &aes_info +}; + +#if defined(POLARSSL_CIPHER_MODE_CFB) +const cipher_info_t aes_128_cfb128_info = { + POLARSSL_CIPHER_AES_128_CFB128, + POLARSSL_MODE_CFB, + 128, + "AES-128-CFB128", + 16, + 16, + &aes_info +}; + +const cipher_info_t aes_192_cfb128_info = { + POLARSSL_CIPHER_AES_192_CFB128, + POLARSSL_MODE_CFB, + 192, + "AES-192-CFB128", + 16, + 16, + &aes_info +}; + +const cipher_info_t aes_256_cfb128_info = { + POLARSSL_CIPHER_AES_256_CFB128, + POLARSSL_MODE_CFB, + 256, + "AES-256-CFB128", + 16, + 16, + &aes_info +}; +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +const cipher_info_t aes_128_ctr_info = { + POLARSSL_CIPHER_AES_128_CTR, + POLARSSL_MODE_CTR, + 128, + "AES-128-CTR", + 16, + 16, + &aes_info +}; + +const cipher_info_t aes_192_ctr_info = { + POLARSSL_CIPHER_AES_192_CTR, + POLARSSL_MODE_CTR, + 192, + "AES-192-CTR", + 16, + 16, + &aes_info +}; + +const cipher_info_t aes_256_ctr_info = { + POLARSSL_CIPHER_AES_256_CTR, + POLARSSL_MODE_CTR, + 256, + "AES-256-CTR", + 16, + 16, + &aes_info +}; +#endif /* POLARSSL_CIPHER_MODE_CTR */ + +#endif + +#if defined(POLARSSL_CAMELLIA_C) + +int camellia_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return camellia_crypt_cbc( (camellia_context *) ctx, operation, length, iv, input, output ); +} + +int camellia_crypt_cfb128_wrap( void *ctx, operation_t operation, size_t length, + size_t *iv_off, unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ +#if defined(POLARSSL_CIPHER_MODE_CFB) + return camellia_crypt_cfb128( (camellia_context *) ctx, operation, length, iv_off, iv, input, output ); +#else + ((void) ctx); + ((void) operation); + ((void) length); + ((void) iv_off); + ((void) iv); + ((void) input); + ((void) output); + + return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE; +#endif +} + +int camellia_crypt_ctr_wrap( void *ctx, size_t length, + size_t *nc_off, unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ +#if defined(POLARSSL_CIPHER_MODE_CTR) + return camellia_crypt_ctr( (camellia_context *) ctx, length, nc_off, nonce_counter, + stream_block, input, output ); +#else + ((void) ctx); + ((void) length); + ((void) nc_off); + ((void) nonce_counter); + ((void) stream_block); + ((void) input); + ((void) output); + + return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE; +#endif +} + +int camellia_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + return camellia_setkey_dec( (camellia_context *) ctx, key, key_length ); +} + +int camellia_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + return camellia_setkey_enc( (camellia_context *) ctx, key, key_length ); +} + +static void * camellia_ctx_alloc( void ) +{ + return malloc( sizeof( camellia_context ) ); +} + +static void camellia_ctx_free( void *ctx ) +{ + free( ctx ); +} + +const cipher_base_t camellia_info = { + POLARSSL_CIPHER_ID_CAMELLIA, + camellia_crypt_cbc_wrap, + camellia_crypt_cfb128_wrap, + camellia_crypt_ctr_wrap, + camellia_setkey_enc_wrap, + camellia_setkey_dec_wrap, + camellia_ctx_alloc, + camellia_ctx_free +}; + +const cipher_info_t camellia_128_cbc_info = { + POLARSSL_CIPHER_CAMELLIA_128_CBC, + POLARSSL_MODE_CBC, + 128, + "CAMELLIA-128-CBC", + 16, + 16, + &camellia_info +}; + +const cipher_info_t camellia_192_cbc_info = { + POLARSSL_CIPHER_CAMELLIA_192_CBC, + POLARSSL_MODE_CBC, + 192, + "CAMELLIA-192-CBC", + 16, + 16, + &camellia_info +}; + +const cipher_info_t camellia_256_cbc_info = { + POLARSSL_CIPHER_CAMELLIA_256_CBC, + POLARSSL_MODE_CBC, + 256, + "CAMELLIA-256-CBC", + 16, + 16, + &camellia_info +}; + +#if defined(POLARSSL_CIPHER_MODE_CFB) +const cipher_info_t camellia_128_cfb128_info = { + POLARSSL_CIPHER_CAMELLIA_128_CFB128, + POLARSSL_MODE_CFB, + 128, + "CAMELLIA-128-CFB128", + 16, + 16, + &camellia_info +}; + +const cipher_info_t camellia_192_cfb128_info = { + POLARSSL_CIPHER_CAMELLIA_192_CFB128, + POLARSSL_MODE_CFB, + 192, + "CAMELLIA-192-CFB128", + 16, + 16, + &camellia_info +}; + +const cipher_info_t camellia_256_cfb128_info = { + POLARSSL_CIPHER_CAMELLIA_256_CFB128, + POLARSSL_MODE_CFB, + 256, + "CAMELLIA-256-CFB128", + 16, + 16, + &camellia_info +}; +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +const cipher_info_t camellia_128_ctr_info = { + POLARSSL_CIPHER_CAMELLIA_128_CTR, + POLARSSL_MODE_CTR, + 128, + "CAMELLIA-128-CTR", + 16, + 16, + &camellia_info +}; + +const cipher_info_t camellia_192_ctr_info = { + POLARSSL_CIPHER_CAMELLIA_192_CTR, + POLARSSL_MODE_CTR, + 192, + "CAMELLIA-192-CTR", + 16, + 16, + &camellia_info +}; + +const cipher_info_t camellia_256_ctr_info = { + POLARSSL_CIPHER_CAMELLIA_256_CTR, + POLARSSL_MODE_CTR, + 256, + "CAMELLIA-256-CTR", + 16, + 16, + &camellia_info +}; +#endif /* POLARSSL_CIPHER_MODE_CTR */ + +#endif + +#if defined(POLARSSL_DES_C) + +int des_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return des_crypt_cbc( (des_context *) ctx, operation, length, iv, input, output ); +} + +int des3_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return des3_crypt_cbc( (des3_context *) ctx, operation, length, iv, input, output ); +} + +int des_crypt_cfb128_wrap( void *ctx, operation_t operation, size_t length, + size_t *iv_off, unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + ((void) ctx); + ((void) operation); + ((void) length); + ((void) iv_off); + ((void) iv); + ((void) input); + ((void) output); + + return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE; +} + +int des_crypt_ctr_wrap( void *ctx, size_t length, + size_t *nc_off, unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + ((void) ctx); + ((void) length); + ((void) nc_off); + ((void) nonce_counter); + ((void) stream_block); + ((void) input); + ((void) output); + + return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE; +} + + +int des_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + ((void) key_length); + + return des_setkey_dec( (des_context *) ctx, key ); +} + +int des_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + ((void) key_length); + + return des_setkey_enc( (des_context *) ctx, key ); +} + +int des3_set2key_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + ((void) key_length); + + return des3_set2key_dec( (des3_context *) ctx, key ); +} + +int des3_set2key_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + ((void) key_length); + + return des3_set2key_enc( (des3_context *) ctx, key ); +} + +int des3_set3key_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + ((void) key_length); + + return des3_set3key_dec( (des3_context *) ctx, key ); +} + +int des3_set3key_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + ((void) key_length); + + return des3_set3key_enc( (des3_context *) ctx, key ); +} + +static void * des_ctx_alloc( void ) +{ + return malloc( sizeof( des_context ) ); +} + +static void * des3_ctx_alloc( void ) +{ + return malloc( sizeof( des3_context ) ); +} + +static void des_ctx_free( void *ctx ) +{ + free( ctx ); +} + +const cipher_base_t des_info = { + POLARSSL_CIPHER_ID_DES, + des_crypt_cbc_wrap, + des_crypt_cfb128_wrap, + des_crypt_ctr_wrap, + des_setkey_enc_wrap, + des_setkey_dec_wrap, + des_ctx_alloc, + des_ctx_free +}; + +const cipher_info_t des_cbc_info = { + POLARSSL_CIPHER_DES_CBC, + POLARSSL_MODE_CBC, + POLARSSL_KEY_LENGTH_DES, + "DES-CBC", + 8, + 8, + &des_info +}; + +const cipher_base_t des_ede_info = { + POLARSSL_CIPHER_ID_DES, + des3_crypt_cbc_wrap, + des_crypt_cfb128_wrap, + des_crypt_ctr_wrap, + des3_set2key_enc_wrap, + des3_set2key_dec_wrap, + des3_ctx_alloc, + des_ctx_free +}; + +const cipher_info_t des_ede_cbc_info = { + POLARSSL_CIPHER_DES_EDE_CBC, + POLARSSL_MODE_CBC, + POLARSSL_KEY_LENGTH_DES_EDE, + "DES-EDE-CBC", + 8, + 8, + &des_ede_info +}; + +const cipher_base_t des_ede3_info = { + POLARSSL_CIPHER_ID_DES, + des3_crypt_cbc_wrap, + des_crypt_cfb128_wrap, + des_crypt_ctr_wrap, + des3_set3key_enc_wrap, + des3_set3key_dec_wrap, + des3_ctx_alloc, + des_ctx_free +}; + +const cipher_info_t des_ede3_cbc_info = { + POLARSSL_CIPHER_DES_EDE3_CBC, + POLARSSL_MODE_CBC, + POLARSSL_KEY_LENGTH_DES_EDE3, + "DES-EDE3-CBC", + 8, + 8, + &des_ede3_info +}; +#endif + +#if defined(POLARSSL_BLOWFISH_C) + +int blowfish_crypt_cbc_wrap( void *ctx, operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return blowfish_crypt_cbc( (blowfish_context *) ctx, operation, length, iv, input, output ); +} + +int blowfish_crypt_cfb64_wrap( void *ctx, operation_t operation, size_t length, + size_t *iv_off, unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ +#if defined(POLARSSL_CIPHER_MODE_CFB) + return blowfish_crypt_cfb64( (blowfish_context *) ctx, operation, length, iv_off, iv, input, output ); +#else + ((void) ctx); + ((void) operation); + ((void) length); + ((void) iv_off); + ((void) iv); + ((void) input); + ((void) output); + + return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE; +#endif +} + +int blowfish_crypt_ctr_wrap( void *ctx, size_t length, + size_t *nc_off, unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ +#if defined(POLARSSL_CIPHER_MODE_CTR) + return blowfish_crypt_ctr( (blowfish_context *) ctx, length, nc_off, nonce_counter, + stream_block, input, output ); +#else + ((void) ctx); + ((void) length); + ((void) nc_off); + ((void) nonce_counter); + ((void) stream_block); + ((void) input); + ((void) output); + + return POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE; +#endif +} + +int blowfish_setkey_dec_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + return blowfish_setkey( (blowfish_context *) ctx, key, key_length ); +} + +int blowfish_setkey_enc_wrap( void *ctx, const unsigned char *key, unsigned int key_length ) +{ + return blowfish_setkey( (blowfish_context *) ctx, key, key_length ); +} + +static void * blowfish_ctx_alloc( void ) +{ + return malloc( sizeof( blowfish_context ) ); +} + +static void blowfish_ctx_free( void *ctx ) +{ + free( ctx ); +} + +const cipher_base_t blowfish_info = { + POLARSSL_CIPHER_ID_BLOWFISH, + blowfish_crypt_cbc_wrap, + blowfish_crypt_cfb64_wrap, + blowfish_crypt_ctr_wrap, + blowfish_setkey_enc_wrap, + blowfish_setkey_dec_wrap, + blowfish_ctx_alloc, + blowfish_ctx_free +}; + +const cipher_info_t blowfish_cbc_info = { + POLARSSL_CIPHER_BLOWFISH_CBC, + POLARSSL_MODE_CBC, + 128, + "BLOWFISH-CBC", + 8, + 8, + &blowfish_info +}; + +#if defined(POLARSSL_CIPHER_MODE_CFB) +const cipher_info_t blowfish_cfb64_info = { + POLARSSL_CIPHER_BLOWFISH_CFB64, + POLARSSL_MODE_CFB, + 128, + "BLOWFISH-CFB64", + 8, + 8, + &blowfish_info +}; +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +const cipher_info_t blowfish_ctr_info = { + POLARSSL_CIPHER_BLOWFISH_CTR, + POLARSSL_MODE_CTR, + 128, + "BLOWFISH-CTR", + 8, + 8, + &blowfish_info +}; +#endif /* POLARSSL_CIPHER_MODE_CTR */ +#endif /* POLARSSL_BLOWFISH_C */ + +#if defined(POLARSSL_CIPHER_NULL_CIPHER) +static void * null_ctx_alloc( void ) +{ + return (void *) 1; +} + + +static void null_ctx_free( void *ctx ) +{ + ((void) ctx); +} + +const cipher_base_t null_base_info = { + POLARSSL_CIPHER_ID_NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + null_ctx_alloc, + null_ctx_free +}; + +const cipher_info_t null_cipher_info = { + POLARSSL_CIPHER_NULL, + POLARSSL_MODE_NULL, + 0, + "NULL", + 1, + 1, + &null_base_info +}; +#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ + +#endif diff --git a/src/libpolarssl/cipher_wrap.h b/src/libpolarssl/cipher_wrap.h new file mode 100644 index 0000000..4abbc4e --- /dev/null +++ b/src/libpolarssl/cipher_wrap.h @@ -0,0 +1,107 @@ +/** + * \file cipher_wrap.h + * + * \brief Cipher wrappers. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_CIPHER_WRAP_H +#define POLARSSL_CIPHER_WRAP_H + +#include "config.h" +#include "cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(POLARSSL_AES_C) + +extern const cipher_info_t aes_128_cbc_info; +extern const cipher_info_t aes_192_cbc_info; +extern const cipher_info_t aes_256_cbc_info; + +#if defined(POLARSSL_CIPHER_MODE_CFB) +extern const cipher_info_t aes_128_cfb128_info; +extern const cipher_info_t aes_192_cfb128_info; +extern const cipher_info_t aes_256_cfb128_info; +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +extern const cipher_info_t aes_128_ctr_info; +extern const cipher_info_t aes_192_ctr_info; +extern const cipher_info_t aes_256_ctr_info; +#endif /* POLARSSL_CIPHER_MODE_CTR */ + +#endif /* defined(POLARSSL_AES_C) */ + +#if defined(POLARSSL_CAMELLIA_C) + +extern const cipher_info_t camellia_128_cbc_info; +extern const cipher_info_t camellia_192_cbc_info; +extern const cipher_info_t camellia_256_cbc_info; + +#if defined(POLARSSL_CIPHER_MODE_CFB) +extern const cipher_info_t camellia_128_cfb128_info; +extern const cipher_info_t camellia_192_cfb128_info; +extern const cipher_info_t camellia_256_cfb128_info; +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +extern const cipher_info_t camellia_128_ctr_info; +extern const cipher_info_t camellia_192_ctr_info; +extern const cipher_info_t camellia_256_ctr_info; +#endif /* POLARSSL_CIPHER_MODE_CTR */ + +#endif /* defined(POLARSSL_CAMELLIA_C) */ + +#if defined(POLARSSL_DES_C) + +extern const cipher_info_t des_cbc_info; +extern const cipher_info_t des_ede_cbc_info; +extern const cipher_info_t des_ede3_cbc_info; + +#endif /* defined(POLARSSL_DES_C) */ + +#if defined(POLARSSL_BLOWFISH_C) +extern const cipher_info_t blowfish_cbc_info; + +#if defined(POLARSSL_CIPHER_MODE_CFB) +extern const cipher_info_t blowfish_cfb64_info; +#endif /* POLARSSL_CIPHER_MODE_CFB */ + +#if defined(POLARSSL_CIPHER_MODE_CTR) +extern const cipher_info_t blowfish_ctr_info; +#endif /* POLARSSL_CIPHER_MODE_CTR */ +#endif /* defined(POLARSSL_BLOWFISH_C) */ + +#if defined(POLARSSL_CIPHER_NULL_CIPHER) +extern const cipher_info_t null_cipher_info; +#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ + +#ifdef __cplusplus +} +#endif + +#endif /* POLARSSL_CIPHER_WRAP_H */ diff --git a/src/libpolarssl/config.h b/src/libpolarssl/config.h new file mode 100644 index 0000000..e476a01 --- /dev/null +++ b/src/libpolarssl/config.h @@ -0,0 +1,1012 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + */ +#ifndef POLARSSL_CONFIG_H +#define POLARSSL_CONFIG_H + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def POLARSSL_HAVE_INT8 + * + * The system uses 8-bit wide native integers. + * + * Uncomment if native integers are 8-bit wide. +#define POLARSSL_HAVE_INT8 + */ + +/** + * \def POLARSSL_HAVE_INT16 + * + * The system uses 16-bit wide native integers. + * + * Uncomment if native integers are 16-bit wide. +#define POLARSSL_HAVE_INT16 + */ + +/** + * \def POLARSSL_HAVE_LONGLONG + * + * The compiler supports the 'long long' type. + * (Only used on 32-bit platforms) + */ +#define POLARSSL_HAVE_LONGLONG + +/** + * \def POLARSSL_HAVE_ASM + * + * The compiler has support for asm() + * + * Uncomment to enable the use of assembly code. + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/polarssl/bn_mul.h + * + */ +#define POLARSSL_HAVE_ASM + +/** + * \def POLARSSL_HAVE_SSE2 + * + * CPU supports SSE2 instruction set. + * + * Uncomment if the CPU supports SSE2 (IA-32 specific). + * + */ +#define POLARSSL_HAVE_SSE2 +/* \} name */ + +/** + * \name SECTION: PolarSSL feature support + * + * This section sets support for features that are or are not needed + * within the modules that are enabled. + * \{ + */ + +/** + * \def POLARSSL_XXX_ALT + * + * Uncomment a macro to let PolarSSL use your alternate core implementation of + * a symmetric or hash algorithm (e.g. platform specific assembly optimized + * implementations). Keep in mind that the function prototypes should remain + * the same. + * + * Example: In case you uncomment POLARSSL_AES_ALT, PolarSSL will no longer + * provide the "struct aes_context" definition and omit the base function + * declarations and implementations. "aes_alt.h" will be included from + * "aes.h" to include the new function definitions. + * + * Uncomment a macro to enable alternate implementation for core algorithm + * functions +#define POLARSSL_AES_ALT +#define POLARSSL_ARC4_ALT +#define POLARSSL_BLOWFISH_ALT +#define POLARSSL_CAMELLIA_ALT +#define POLARSSL_DES_ALT +#define POLARSSL_XTEA_ALT +#define POLARSSL_MD2_ALT +#define POLARSSL_MD4_ALT +#define POLARSSL_MD5_ALT +#define POLARSSL_SHA1_ALT +#define POLARSSL_SHA2_ALT +#define POLARSSL_SHA4_ALT + */ + +/** + * \def POLARSSL_AES_ROM_TABLES + * + * Store the AES tables in ROM. + * + * Uncomment this macro to store the AES tables in ROM. + * +#define POLARSSL_AES_ROM_TABLES + */ + +/** + * \def POLARSSL_CIPHER_MODE_CFB + * + * Enable Cipher Feedback mode (CFB) for symmetric ciphers. + */ +#define POLARSSL_CIPHER_MODE_CFB + +/** + * \def POLARSSL_CIPHER_MODE_CTR + * + * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. + */ +#define POLARSSL_CIPHER_MODE_CTR + +/** + * \def POLARSSL_CIPHER_NULL_CIPHER + * + * Enable NULL cipher. + * Warning: Only do so when you know what you are doing. This allows for + * encryption or channels without any security! + * + * Requires POLARSSL_ENABLE_WEAK_CIPHERSUITES as well to enable + * the following ciphersuites: + * TLS_RSA_WITH_NULL_MD5 + * TLS_RSA_WITH_NULL_SHA + * TLS_RSA_WITH_NULL_SHA256 + * + * Uncomment this macro to enable the NULL cipher and ciphersuites +#define POLARSSL_CIPHER_NULL_CIPHER + */ + +/** + * \def POLARSSL_ENABLE_WEAK_CIPHERSUITES + * + * Enable weak ciphersuites in SSL / TLS + * Warning: Only do so when you know what you are doing. This allows for + * channels with virtually no security at all! + * + * This enables the following ciphersuites: + * TLS_RSA_WITH_DES_CBC_SHA + * TLS_DHE_RSA_WITH_DES_CBC_SHA + * + * Uncomment this macro to enable weak ciphersuites + */ +#define POLARSSL_ENABLE_WEAK_CIPHERSUITES + +/** + * \def POLARSSL_ERROR_STRERROR_DUMMY + * + * Enable a dummy error function to make use of error_strerror() in + * third party libraries easier. + * + * Disable if you run into name conflicts and want to really remove the + * error_strerror() + */ +#define POLARSSL_ERROR_STRERROR_DUMMY + +/** + * \def POLARSSL_GENPRIME + * + * Requires: POLARSSL_BIGNUM_C, POLARSSL_RSA_C + * + * Enable the RSA prime-number generation code. + */ +#define POLARSSL_GENPRIME + +/** + * \def POLARSSL_FS_IO + * + * Enable functions that use the filesystem. + */ +#define POLARSSL_FS_IO + +/** + * \def POLARSSL_NO_DEFAULT_ENTROPY_SOURCES + * + * Do not add default entropy sources. These are the platform specific, + * hardclock and HAVEGE based poll functions. + * + * This is useful to have more control over the added entropy sources in an + * application. + * + * Uncomment this macro to prevent loading of default entropy functions. +#define POLARSSL_NO_DEFAULT_ENTROPY_SOURCES + */ + +/** + * \def POLARSSL_NO_PLATFORM_ENTROPY + * + * Do not use built-in platform entropy functions. + * This is useful if your platform does not support + * standards like the /dev/urandom or Windows CryptoAPI. + * + * Uncomment this macro to disable the built-in platform entropy functions. +#define POLARSSL_NO_PLATFORM_ENTROPY + */ + +/** + * \def POLARSSL_PKCS1_V21 + * + * Requires: POLARSSL_MD_C, POLARSSL_RSA_C + * + * Enable support for PKCS#1 v2.1 encoding. + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define POLARSSL_PKCS1_V21 + +/** + * \def POLARSSL_RSA_NO_CRT + * + * Do not use the Chinese Remainder Theorem for the RSA private operation. + * + * Uncomment this macro to disable the use of CRT in RSA. + * +#define POLARSSL_RSA_NO_CRT + */ + +/** + * \def POLARSSL_SELF_TEST + * + * Enable the checkup functions (*_self_test). +#define POLARSSL_SELF_TEST + */ + +/** + * \def POLARSSL_SSL_ALL_ALERT_MESSAGES + * + * Enable sending of alert messages in case of encountered errors as per RFC. + * If you choose not to send the alert messages, PolarSSL can still communicate + * with other servers, only debugging of failures is harder. + * + * The advantage of not sending alert messages, is that no information is given + * about reasons for failures thus preventing adversaries of gaining intel. + * + * Enable sending of all alert messages +#define POLARSSL_SSL_ALERT_MESSAGES + */ + +/** + * \def POLARSSL_SSL_DEBUG_ALL + * + * Enable the debug messages in SSL module for all issues. + * Debug messages have been disabled in some places to prevent timing + * attacks due to (unbalanced) debugging function calls. + * + * If you need all error reporting you should enable this during debugging, + * but remove this for production servers that should log as well. + * + * Uncomment this macro to report all debug messages on errors introducing + * a timing side-channel. + * +#define POLARSSL_SSL_DEBUG_ALL + */ + +/** + * \def POLARSSL_SSL_HW_RECORD_ACCEL + * + * Enable hooking functions in SSL module for hardware acceleration of + * individual records. + * + * Uncomment this macro to enable hooking functions. +#define POLARSSL_SSL_HW_RECORD_ACCEL + */ + +/** + * \def POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + * + * Enable support for receiving and parsing SSLv2 Client Hello messages for the + * SSL Server module (POLARSSL_SSL_SRV_C) + * + * Comment this macro to disable support for SSLv2 Client Hello messages. + */ +#define POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + +/** + * \def POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an unknown critical extension. + * + * Uncomment to prevent an error. + * + */ +#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + +/** + * \def POLARSSL_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and + * decompression of packet data. + * + * Used in: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This feature requires zlib library and headers to be present. + * + * Uncomment to enable use of ZLIB + */ +#define POLARSSL_ZLIB_SUPPORT +/* \} name */ + +/** + * \name SECTION: PolarSSL modules + * + * This section enables or disables entire modules in PolarSSL + * \{ + */ + +/** + * \def POLARSSL_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/ssl_tls.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_RSA_WITH_AES_128_CBC_SHA + * TLS_RSA_WITH_AES_256_CBC_SHA + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * TLS_RSA_WITH_AES_128_CBC_SHA256 + * TLS_RSA_WITH_AES_256_CBC_SHA256 + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * TLS_RSA_WITH_AES_128_GCM_SHA256 + * TLS_RSA_WITH_AES_256_GCM_SHA384 + * + * PEM uses AES for decrypting encrypted keys. + */ +#define POLARSSL_AES_C + +/** + * \def POLARSSL_ARC4_C + * + * Enable the ARCFOUR stream cipher. + * + * Module: library/arc4.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites: + * TLS_RSA_WITH_RC4_128_MD5 + * TLS_RSA_WITH_RC4_128_SHA + */ +#define POLARSSL_ARC4_C + +/** + * \def POLARSSL_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509parse.c + */ +#define POLARSSL_ASN1_PARSE_C + +/** + * \def POLARSSL_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + */ +#define POLARSSL_ASN1_WRITE_C + +/** + * \def POLARSSL_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +#define POLARSSL_BASE64_C + +/** + * \def POLARSSL_BIGNUM_C + * + * Enable the multi-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/rsa.c + * library/ssl_tls.c + * library/x509parse.c + * + * This module is required for RSA and DHM support. + */ +#define POLARSSL_BIGNUM_C + +/** + * \def POLARSSL_BLOWFISH_C + * + * Enable the Blowfish block cipher. + * + * Module: library/blowfish.c + */ +#define POLARSSL_BLOWFISH_C + +/** + * \def POLARSSL_CAMELLIA_C + * + * Enable the Camellia block cipher. + * + * Module: library/camellia.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + */ +#define POLARSSL_CAMELLIA_C + +/** + * \def POLARSSL_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * This module is used for testing (ssl_client/server). + */ +#define POLARSSL_CERTS_C + +/** + * \def POLARSSL_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: + * + * Uncomment to enable generic cipher wrappers. + */ +#define POLARSSL_CIPHER_C + +/** + * \def POLARSSL_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-256-based random generator + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: POLARSSL_AES_C + * + * This module provides the CTR_DRBG AES-256 random number generator. + */ +#define POLARSSL_CTR_DRBG_C + +/** + * \def POLARSSL_DEBUG_C + * + * Enable the debug functions. + * + * Module: library/debug.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module provides debugging functions. +#define POLARSSL_DEBUG_C + */ + +/** + * \def POLARSSL_DES_C + * + * Enable the DES block cipher. + * + * Module: library/des.c + * Caller: library/pem.c + * library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * + * PEM uses DES/3DES for decrypting encrypted keys. + */ +#define POLARSSL_DES_C + +/** + * \def POLARSSL_DHM_C + * + * Enable the Diffie-Hellman-Merkle key exchange. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_DHE_RSA_WITH_DES_CBC_SHA + * TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + */ +#define POLARSSL_DHM_C + +/** + * \def POLARSSL_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: POLARSSL_SHA4_C + * + * This module provides a generic entropy pool + */ +#define POLARSSL_ENTROPY_C + +/** + * \def POLARSSL_ERROR_C + * + * Enable error code to error string conversion. + * + * Module: library/error.c + * Caller: + * + * This module enables err_strerror(). + */ +#define POLARSSL_ERROR_C + +/** + * \def POLARSSL_GCM_C + * + * Enable the Galois/Counter Mode (GCM) for AES + * + * Module: library/gcm.c + * + * Requires: POLARSSL_AES_C + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_RSA_WITH_AES_128_GCM_SHA256 + * TLS_RSA_WITH_AES_256_GCM_SHA384 + */ +#define POLARSSL_GCM_C + +/** + * \def POLARSSL_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Warning: the HAVEGE random generator is not suitable for virtualized + * environments + * + * Warning: the HAVEGE random generator is dependent on timing and specific + * processor traits. It is therefore not advised to use HAVEGE as + * your applications primary random generator or primary entropy pool + * input. As a secondary input to your entropy pool, it IS able add + * the (limited) extra entropy it provides. + * + * Module: library/havege.c + * Caller: + * + * Requires: POLARSSL_TIMING_C + * + * Uncomment to enable the HAVEGE random generator. + */ +#define POLARSSL_HAVEGE_C + +/** + * \def POLARSSL_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define POLARSSL_MD_C + +/** + * \def POLARSSL_MD2_C + * + * Enable the MD2 hash algorithm + * + * Module: library/md2.c + * Caller: library/x509parse.c + * + * Uncomment to enable support for (rare) MD2-signed X.509 certs. + * + */ +#define POLARSSL_MD2_C + +/** + * \def POLARSSL_MD4_C + * + * Enable the MD4 hash algorithm + * + * Module: library/md4.c + * Caller: library/x509parse.c + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + * + */ +#define POLARSSL_MD4_C + +/** + * \def POLARSSL_MD5_C + * + * Enable the MD5 hash algorithm + * + * Module: library/md5.c + * Caller: library/pem.c + * library/ssl_tls.c + * library/x509parse.c + * + * This module is required for SSL/TLS and X.509. + * PEM uses MD5 for decrypting encrypted keys. + */ +#define POLARSSL_MD5_C + +/** + * \def POLARSSL_NET_C + * + * Enable the TCP/IP networking routines. + * + * Module: library/net.c + * Caller: + * + * This module provides TCP/IP networking routines. + */ +#define POLARSSL_NET_C + +/** + * \def POLARSSL_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * This modules adds support for the VIA PadLock on x86. +#define POLARSSL_PADLOCK_C + */ + +/** + * \def POLARSSL_PBKDF2_C + * + * Enable PKCS#5 PBKDF2 key derivation function + * DEPRECATED: Use POLARSSL_PKCS5_C instead + * + * Module: library/pbkdf2.c + * + * Requires: POLARSSL_PKCS5_C + * + * This module adds support for the PKCS#5 PBKDF2 key derivation function. + */ +#define POLARSSL_PBKDF2_C + +/** + * \def POLARSSL_PEM_C + * + * Enable PEM decoding + * + * Module: library/pem.c + * Caller: library/x509parse.c + * + * Requires: POLARSSL_BASE64_C + * + * This modules adds support for decoding PEM files. + */ +#define POLARSSL_PEM_C + +/** + * \def POLARSSL_PKCS5_C + * + * Enable PKCS#5 functions + * + * Module: library/pkcs5.c + * + * Requires: POLARSSL_MD_C + * + * This module adds support for the PKCS#5 functions. + */ +#define POLARSSL_PKCS5_C + +/** + * \def POLARSSL_PKCS11_C + * + * Enable wrapper for PKCS#11 smartcard support. + * + * Module: library/ssl_srv.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: POLARSSL_SSL_TLS_C + * + * This module enables SSL/TLS PKCS #11 smartcard support. + * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) +#define POLARSSL_PKCS11_C + */ + +/** + * \def POLARSSL_PKCS12_C + * + * Enable PKCS#12 PBE functions + * Adds algorithms for parsing PKCS#8 encrypted private keys + * + * Module: library/pkcs12.c + * Caller: library/x509parse.c + * + * Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_CIPHER_C, POLARSSL_MD_C + * Can use: POLARSSL_ARC4_C + * + * This module enables PKCS#12 functions. + */ +#define POLARSSL_PKCS12_C + +/** + * \def POLARSSL_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * Requires: POLARSSL_BIGNUM_C + * + * This module is required for SSL/TLS and MD5-signed certificates. + */ +#define POLARSSL_RSA_C + +/** + * \def POLARSSL_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/sha1.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509parse.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +#define POLARSSL_SHA1_C + +/** + * \def POLARSSL_SHA2_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/sha2.c + * Caller: library/md_wrap.c + * library/x509parse.c + * + * This module adds support for SHA-224 and SHA-256. + * This module is required for the SSL/TLS 1.2 PRF function. + */ +#define POLARSSL_SHA2_C + +/** + * \def POLARSSL_SHA4_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * + * Module: library/sha4.c + * Caller: library/md_wrap.c + * library/x509parse.c + * + * This module adds support for SHA-384 and SHA-512. + */ +#define POLARSSL_SHA4_C + +/** + * \def POLARSSL_SSL_CACHE_C + * + * Enable simple SSL cache implementation. + * + * Module: library/ssl_cache.c + * Caller: + * + * Requires: POLARSSL_SSL_CACHE_C +#define POLARSSL_SSL_CACHE_C + */ + +/** + * \def POLARSSL_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: POLARSSL_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +#define POLARSSL_SSL_CLI_C + +/** + * \def POLARSSL_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: POLARSSL_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +#define POLARSSL_SSL_SRV_C + +/** + * \def POLARSSL_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: POLARSSL_MD5_C, POLARSSL_SHA1_C, POLARSSL_X509_PARSE_C + * + * This module is required for SSL/TLS. + */ +#define POLARSSL_SSL_TLS_C + +/** + * \def POLARSSL_TIMING_C + * + * Enable the portable timing interface. + * + * Module: library/timing.c + * Caller: library/havege.c + * + * This module is used by the HAVEGE random number generator. + */ +#define POLARSSL_TIMING_C + +/** + * \def POLARSSL_VERSION_C + * + * Enable run-time version information. + * + * Module: library/version.c + * + * This module provides run-time version information. + */ +#define POLARSSL_VERSION_C + +/** + * \def POLARSSL_X509_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/x509parse.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_BIGNUM_C, POLARSSL_RSA_C + * + * This module is required for X.509 certificate parsing. + */ +#define POLARSSL_X509_PARSE_C + +/** + * \def POLARSSL_X509_WRITE_C + * + * Enable X.509 buffer writing. + * + * Module: library/x509write.c + * + * Requires: POLARSSL_BIGNUM_C, POLARSSL_RSA_C + * + * This module is required for X.509 certificate request writing. + */ +#define POLARSSL_X509_WRITE_C + +/** + * \def POLARSSL_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +#define POLARSSL_XTEA_C +/* \} name */ + +/** + * \name SECTION: Module configuration options + * + * This section allows for the setting of module specific sizes and + * configuration options. The default values are already present in the + * relevant header files and should suffice for the regular use cases. + * Our advice is to enable POLARSSL_CONFIG_OPTIONS and change values here + * only if you have a good reason and know the consequences. + * + * If POLARSSL_CONFIG_OPTIONS is undefined here the options in the module + * header file take precedence. + * + * Please check the respective header file for documentation on these + * parameters (to prevent duplicate documentation). + * + * Uncomment POLARSSL_CONFIG_OPTIONS to enable using the values defined here. + * \{ + */ +//#define POLARSSL_CONFIG_OPTIONS /**< Enable config.h module value configuration */ + +#if defined(POLARSSL_CONFIG_OPTIONS) + +// MPI / BIGNUM options +// +#define POLARSSL_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +#define POLARSSL_MPI_MAX_SIZE 512 /**< Maximum number of bytes for usable MPIs. */ + +// CTR_DRBG options +// +#define CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default */ +#define CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +#define CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +#define CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +#define CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +// Entropy options +// +#define ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +#define ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ + +// SSL Cache options +// +#define SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ +#define SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ + +// SSL options +// +#define SSL_MAX_CONTENT_LEN 16384 /**< Size of the input / output buffer */ + +#endif /* POLARSSL_CONFIG_OPTIONS */ + +/* \} name */ +#endif /* config.h */ diff --git a/src/libpolarssl/ctr_drbg.c b/src/libpolarssl/ctr_drbg.c new file mode 100644 index 0000000..06b2027 --- /dev/null +++ b/src/libpolarssl/ctr_drbg.c @@ -0,0 +1,562 @@ +/* + * CTR_DRBG implementation based on AES-256 (NIST SP 800-90) + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The NIST SP 800-90 DRBGs are described in the following publucation. + * + * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf + */ + +#include "config.h" + +#if defined(POLARSSL_CTR_DRBG_C) + +#include "ctr_drbg.h" + +#if defined(POLARSSL_FS_IO) +#include +#endif + +/* + * Non-public function wrapped by ctr_crbg_init(). Necessary to allow NIST + * tests to succeed (which require known length fixed entropy) + */ +int ctr_drbg_init_entropy_len( + ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len, + size_t entropy_len ) +{ + int ret; + unsigned char key[CTR_DRBG_KEYSIZE]; + + memset( ctx, 0, sizeof(ctr_drbg_context) ); + memset( key, 0, CTR_DRBG_KEYSIZE ); + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + ctx->entropy_len = entropy_len; + ctx->reseed_interval = CTR_DRBG_RESEED_INTERVAL; + + /* + * Initialize with an empty key + */ + aes_setkey_enc( &ctx->aes_ctx, key, CTR_DRBG_KEYBITS ); + + if( ( ret = ctr_drbg_reseed( ctx, custom, len ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +int ctr_drbg_init( ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ) +{ + return( ctr_drbg_init_entropy_len( ctx, f_entropy, p_entropy, custom, len, + CTR_DRBG_ENTROPY_LEN ) ); +} + +void ctr_drbg_set_prediction_resistance( ctr_drbg_context *ctx, int resistance ) +{ + ctx->prediction_resistance = resistance; +} + +void ctr_drbg_set_entropy_len( ctr_drbg_context *ctx, size_t len ) +{ + ctx->entropy_len = len; +} + +void ctr_drbg_set_reseed_interval( ctr_drbg_context *ctx, int interval ) +{ + ctx->reseed_interval = interval; +} + +int block_cipher_df( unsigned char *output, + const unsigned char *data, size_t data_len ) +{ + unsigned char buf[CTR_DRBG_MAX_SEED_INPUT + CTR_DRBG_BLOCKSIZE + 16]; + unsigned char tmp[CTR_DRBG_SEEDLEN]; + unsigned char key[CTR_DRBG_KEYSIZE]; + unsigned char chain[CTR_DRBG_BLOCKSIZE]; + unsigned char *p = buf, *iv; + aes_context aes_ctx; + + int i, j, buf_len, use_len; + + memset( buf, 0, CTR_DRBG_MAX_SEED_INPUT + CTR_DRBG_BLOCKSIZE + 16 ); + + /* + * Construct IV (16 bytes) and S in buffer + * IV = Counter (in 32-bits) padded to 16 with zeroes + * S = Length input string (in 32-bits) || Length of output (in 32-bits) || + * data || 0x80 + * (Total is padded to a multiple of 16-bytes with zeroes) + */ + p = buf + CTR_DRBG_BLOCKSIZE; + *p++ = ( data_len >> 24 ) & 0xff; + *p++ = ( data_len >> 16 ) & 0xff; + *p++ = ( data_len >> 8 ) & 0xff; + *p++ = ( data_len ) & 0xff; + p += 3; + *p++ = CTR_DRBG_SEEDLEN; + memcpy( p, data, data_len ); + p[data_len] = 0x80; + + buf_len = CTR_DRBG_BLOCKSIZE + 8 + data_len + 1; + + for( i = 0; i < CTR_DRBG_KEYSIZE; i++ ) + key[i] = i; + + aes_setkey_enc( &aes_ctx, key, CTR_DRBG_KEYBITS ); + + /* + * Reduce data to POLARSSL_CTR_DRBG_SEEDLEN bytes of data + */ + for( j = 0; j < CTR_DRBG_SEEDLEN; j += CTR_DRBG_BLOCKSIZE ) + { + p = buf; + memset( chain, 0, CTR_DRBG_BLOCKSIZE ); + use_len = buf_len; + + while( use_len > 0 ) + { + for( i = 0; i < CTR_DRBG_BLOCKSIZE; i++ ) + chain[i] ^= p[i]; + p += CTR_DRBG_BLOCKSIZE; + use_len -= CTR_DRBG_BLOCKSIZE; + + aes_crypt_ecb( &aes_ctx, AES_ENCRYPT, chain, chain ); + } + + memcpy( tmp + j, chain, CTR_DRBG_BLOCKSIZE ); + + /* + * Update IV + */ + buf[3]++; + } + + /* + * Do final encryption with reduced data + */ + aes_setkey_enc( &aes_ctx, tmp, CTR_DRBG_KEYBITS ); + iv = tmp + CTR_DRBG_KEYSIZE; + p = output; + + for( j = 0; j < CTR_DRBG_SEEDLEN; j += CTR_DRBG_BLOCKSIZE ) + { + aes_crypt_ecb( &aes_ctx, AES_ENCRYPT, iv, iv ); + memcpy( p, iv, CTR_DRBG_BLOCKSIZE ); + p += CTR_DRBG_BLOCKSIZE; + } + + return( 0 ); +} + +int ctr_drbg_update_internal( ctr_drbg_context *ctx, + const unsigned char data[CTR_DRBG_SEEDLEN] ) +{ + unsigned char tmp[CTR_DRBG_SEEDLEN]; + unsigned char *p = tmp; + int i, j; + + memset( tmp, 0, CTR_DRBG_SEEDLEN ); + + for( j = 0; j < CTR_DRBG_SEEDLEN; j += CTR_DRBG_BLOCKSIZE ) + { + /* + * Increase counter + */ + for( i = CTR_DRBG_BLOCKSIZE; i > 0; i-- ) + if( ++ctx->counter[i - 1] != 0 ) + break; + + /* + * Crypt counter block + */ + aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, ctx->counter, p ); + + p += CTR_DRBG_BLOCKSIZE; + } + + for( i = 0; i < CTR_DRBG_SEEDLEN; i++ ) + tmp[i] ^= data[i]; + + /* + * Update key and counter + */ + aes_setkey_enc( &ctx->aes_ctx, tmp, CTR_DRBG_KEYBITS ); + memcpy( ctx->counter, tmp + CTR_DRBG_KEYSIZE, CTR_DRBG_BLOCKSIZE ); + + return( 0 ); +} + +void ctr_drbg_update( ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ) +{ + unsigned char add_input[CTR_DRBG_SEEDLEN]; + + if( add_len > 0 ) + { + block_cipher_df( add_input, additional, add_len ); + ctr_drbg_update_internal( ctx, add_input ); + } +} + +int ctr_drbg_reseed( ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ) +{ + unsigned char seed[CTR_DRBG_MAX_SEED_INPUT]; + size_t seedlen = 0; + + if( ctx->entropy_len + len > CTR_DRBG_MAX_SEED_INPUT ) + return( POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( seed, 0, CTR_DRBG_MAX_SEED_INPUT ); + + /* + * Gather enropy_len bytes of entropy to seed state + */ + if( 0 != ctx->f_entropy( ctx->p_entropy, seed, + ctx->entropy_len ) ) + { + return( POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED ); + } + + seedlen += ctx->entropy_len; + + /* + * Add additional data + */ + if( additional && len ) + { + memcpy( seed + seedlen, additional, len ); + seedlen += len; + } + + /* + * Reduce to 384 bits + */ + block_cipher_df( seed, seed, seedlen ); + + /* + * Update state + */ + ctr_drbg_update_internal( ctx, seed ); + ctx->reseed_counter = 1; + + return( 0 ); +} + +int ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ) +{ + int ret = 0; + ctr_drbg_context *ctx = (ctr_drbg_context *) p_rng; + unsigned char add_input[CTR_DRBG_SEEDLEN]; + unsigned char *p = output; + unsigned char tmp[CTR_DRBG_BLOCKSIZE]; + int i; + size_t use_len; + + if( output_len > CTR_DRBG_MAX_REQUEST ) + return( POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG ); + + if( add_len > CTR_DRBG_MAX_INPUT ) + return( POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( add_input, 0, CTR_DRBG_SEEDLEN ); + + if( ctx->reseed_counter > ctx->reseed_interval || + ctx->prediction_resistance ) + { + if( ( ret = ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 ) + return( ret ); + + add_len = 0; + } + + if( add_len > 0 ) + { + block_cipher_df( add_input, additional, add_len ); + ctr_drbg_update_internal( ctx, add_input ); + } + + while( output_len > 0 ) + { + /* + * Increase counter + */ + for( i = CTR_DRBG_BLOCKSIZE; i > 0; i-- ) + if( ++ctx->counter[i - 1] != 0 ) + break; + + /* + * Crypt counter block + */ + aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, ctx->counter, tmp ); + + use_len = (output_len > CTR_DRBG_BLOCKSIZE ) ? CTR_DRBG_BLOCKSIZE : output_len; + /* + * Copy random block to destination + */ + memcpy( p, tmp, use_len ); + p += use_len; + output_len -= use_len; + } + + ctr_drbg_update_internal( ctx, add_input ); + + ctx->reseed_counter++; + + return( 0 ); +} + +int ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len ) +{ + return ctr_drbg_random_with_add( p_rng, output, output_len, NULL, 0 ); +} + +#if defined(POLARSSL_FS_IO) +int ctr_drbg_write_seed_file( ctr_drbg_context *ctx, const char *path ) +{ + int ret; + FILE *f; + unsigned char buf[ CTR_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR ); + + if( ( ret = ctr_drbg_random( ctx, buf, CTR_DRBG_MAX_INPUT ) ) != 0 ) + return( ret ); + + if( fwrite( buf, 1, CTR_DRBG_MAX_INPUT, f ) != CTR_DRBG_MAX_INPUT ) + { + fclose( f ); + return( POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR ); + } + + fclose( f ); + return( 0 ); +} + +int ctr_drbg_update_seed_file( ctr_drbg_context *ctx, const char *path ) +{ + FILE *f; + size_t n; + unsigned char buf[ CTR_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > CTR_DRBG_MAX_INPUT ) + return( POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + if( fread( buf, 1, n, f ) != n ) + { + fclose( f ); + return( POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR ); + } + + ctr_drbg_update( ctx, buf, n ); + + fclose( f ); + + return( ctr_drbg_write_seed_file( ctx, path ) ); +} +#endif /* POLARSSL_FS_IO */ + +#if defined(POLARSSL_SELF_TEST) + +#include + +unsigned char entropy_source_pr[96] = + { 0xc1, 0x80, 0x81, 0xa6, 0x5d, 0x44, 0x02, 0x16, + 0x19, 0xb3, 0xf1, 0x80, 0xb1, 0xc9, 0x20, 0x02, + 0x6a, 0x54, 0x6f, 0x0c, 0x70, 0x81, 0x49, 0x8b, + 0x6e, 0xa6, 0x62, 0x52, 0x6d, 0x51, 0xb1, 0xcb, + 0x58, 0x3b, 0xfa, 0xd5, 0x37, 0x5f, 0xfb, 0xc9, + 0xff, 0x46, 0xd2, 0x19, 0xc7, 0x22, 0x3e, 0x95, + 0x45, 0x9d, 0x82, 0xe1, 0xe7, 0x22, 0x9f, 0x63, + 0x31, 0x69, 0xd2, 0x6b, 0x57, 0x47, 0x4f, 0xa3, + 0x37, 0xc9, 0x98, 0x1c, 0x0b, 0xfb, 0x91, 0x31, + 0x4d, 0x55, 0xb9, 0xe9, 0x1c, 0x5a, 0x5e, 0xe4, + 0x93, 0x92, 0xcf, 0xc5, 0x23, 0x12, 0xd5, 0x56, + 0x2c, 0x4a, 0x6e, 0xff, 0xdc, 0x10, 0xd0, 0x68 }; + +unsigned char entropy_source_nopr[64] = + { 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, 0x14, + 0x54, 0xde, 0xf6, 0x75, 0xfb, 0x79, 0x58, 0xfe, + 0xc7, 0xdb, 0x87, 0x3e, 0x56, 0x89, 0xfc, 0x9d, + 0x03, 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, 0x20, + 0xf9, 0xe6, 0x5e, 0x04, 0xd8, 0x56, 0xf3, 0xa9, + 0xc4, 0x4a, 0x4c, 0xbd, 0xc1, 0xd0, 0x08, 0x46, + 0xf5, 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, 0x7e, + 0x4e, 0x0f, 0x9d, 0x8e, 0xf4, 0x09, 0xf9, 0x2e }; + +unsigned char nonce_pers_pr[16] = + { 0xd2, 0x54, 0xfc, 0xff, 0x02, 0x1e, 0x69, 0xd2, + 0x29, 0xc9, 0xcf, 0xad, 0x85, 0xfa, 0x48, 0x6c }; + +unsigned char nonce_pers_nopr[16] = + { 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5, + 0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f }; + +unsigned char result_pr[16] = + { 0x34, 0x01, 0x16, 0x56, 0xb4, 0x29, 0x00, 0x8f, + 0x35, 0x63, 0xec, 0xb5, 0xf2, 0x59, 0x07, 0x23 }; + +unsigned char result_nopr[16] = + { 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, 0x88, + 0x9d, 0x90, 0x3e, 0x07, 0x7c, 0x6f, 0x21, 0x8f }; + +int test_offset; +int ctr_drbg_self_test_entropy( void *data, unsigned char *buf, size_t len ) +{ + unsigned char *p = data; + memcpy( buf, p + test_offset, len ); + test_offset += 32; + return( 0 ); +} + +/* + * Checkup routine + */ +int ctr_drbg_self_test( int verbose ) +{ + ctr_drbg_context ctx; + unsigned char buf[16]; + + /* + * Based on a NIST CTR_DRBG test vector (PR = True) + */ + if( verbose != 0 ) + printf( " CTR_DRBG (PR = TRUE) : " ); + + test_offset = 0; + if( ctr_drbg_init_entropy_len( &ctx, ctr_drbg_self_test_entropy, entropy_source_pr, nonce_pers_pr, 16, 32 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + ctr_drbg_set_prediction_resistance( &ctx, CTR_DRBG_PR_ON ); + + if( ctr_drbg_random( &ctx, buf, CTR_DRBG_BLOCKSIZE ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( ctr_drbg_random( &ctx, buf, CTR_DRBG_BLOCKSIZE ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( memcmp( buf, result_pr, CTR_DRBG_BLOCKSIZE ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + /* + * Based on a NIST CTR_DRBG test vector (PR = FALSE) + */ + if( verbose != 0 ) + printf( " CTR_DRBG (PR = FALSE): " ); + + test_offset = 0; + if( ctr_drbg_init_entropy_len( &ctx, ctr_drbg_self_test_entropy, entropy_source_nopr, nonce_pers_nopr, 16, 32 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( ctr_drbg_random( &ctx, buf, 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( ctr_drbg_reseed( &ctx, NULL, 0 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( ctr_drbg_random( &ctx, buf, 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( memcmp( buf, result_nopr, 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} +#endif + +#endif diff --git a/src/libpolarssl/ctr_drbg.h b/src/libpolarssl/ctr_drbg.h new file mode 100644 index 0000000..5a26cde --- /dev/null +++ b/src/libpolarssl/ctr_drbg.h @@ -0,0 +1,231 @@ +/** + * \file ctr_drbg.h + * + * \brief CTR_DRBG based on AES-256 (NIST SP 800-90) + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_CTR_DRBG_H +#define POLARSSL_CTR_DRBG_H + +#include + +#include "aes.h" + +#define POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED -0x0034 /**< The entropy source failed. */ +#define POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG -0x0036 /**< Too many random requested in single call. */ +#define POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 /**< Input too large (Entropy + additional). */ +#define POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A /**< Read/write error in file. */ + +#define CTR_DRBG_BLOCKSIZE 16 /**< Block size used by the cipher */ +#define CTR_DRBG_KEYSIZE 32 /**< Key size used by the cipher */ +#define CTR_DRBG_KEYBITS ( CTR_DRBG_KEYSIZE * 8 ) +#define CTR_DRBG_SEEDLEN ( CTR_DRBG_KEYSIZE + CTR_DRBG_BLOCKSIZE ) + /**< The seed length (counter + AES key) */ + +#if !defined(POLARSSL_CONFIG_OPTIONS) +#define CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default */ +#define CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +#define CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +#define CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +#define CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ +#endif /* !POLARSSL_CONFIG_OPTIONS */ + +#define CTR_DRBG_PR_OFF 0 /**< No prediction resistance */ +#define CTR_DRBG_PR_ON 1 /**< Prediction resistance enabled */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CTR_DRBG context structure + */ +typedef struct +{ + unsigned char counter[16]; /*!< counter (V) */ + int reseed_counter; /*!< reseed counter */ + int prediction_resistance; /*!< enable prediction resistance (Automatic + reseed before every random generation) */ + size_t entropy_len; /*!< amount of entropy grabbed on each (re)seed */ + int reseed_interval; /*!< reseed interval */ + + aes_context aes_ctx; /*!< AES context */ + + /* + * Callbacks (Entropy) + */ + int (*f_entropy)(void *, unsigned char *, size_t); + + void *p_entropy; /*!< context for the entropy function */ +} +ctr_drbg_context; + +/** + * \brief CTR_DRBG initialization + * + * Note: Personalization data can be provided in addition to the more generic + * entropy source to make this instantiation as unique as possible. + * + * \param ctx CTR_DRBG context to be initialized + * \param f_entropy Entropy callback (p_entropy, buffer to fill, buffer + * length) + * \param p_entropy Entropy context + * \param custom Personalization data (Device specific identifiers) + * (Can be NULL) + * \param len Length of personalization data + * + * \return 0 if successful, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int ctr_drbg_init( ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ); + +/** + * \brief Enable / disable prediction resistance (Default: Off) + * + * Note: If enabled, entropy is used for ctx->entropy_len before each call! + * Only use this if you have ample supply of good entropy! + * + * \param ctx CTR_DRBG context + * \param resistance CTR_DRBG_PR_ON or CTR_DRBG_PR_OFF + */ +void ctr_drbg_set_prediction_resistance( ctr_drbg_context *ctx, + int resistance ); + +/** + * \brief Set the amount of entropy grabbed on each (re)seed + * (Default: CTR_DRBG_ENTROPY_LEN) + * + * \param ctx CTR_DRBG context + * \param len Amount of entropy to grab + */ +void ctr_drbg_set_entropy_len( ctr_drbg_context *ctx, + size_t len ); + +/** + * \brief Set the reseed interval + * (Default: CTR_DRBG_RESEED_INTERVAL) + * + * \param ctx CTR_DRBG context + * \param interval Reseed interval + */ +void ctr_drbg_set_reseed_interval( ctr_drbg_context *ctx, + int interval ); + +/** + * \brief CTR_DRBG reseeding (extracts data from entropy source) + * + * \param ctx CTR_DRBG context + * \param additional Additional data to add to state (Can be NULL) + * \param len Length of additional data + * + * \return 0 if successful, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int ctr_drbg_reseed( ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ); + +/** + * \brief CTR_DRBG update state + * + * \param ctx CTR_DRBG context + * \param additional Additional data to update state with + * \param add_len Length of additional data + */ +void ctr_drbg_update( ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); + +/** + * \brief CTR_DRBG generate random with additional update input + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \param p_rng CTR_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * \param additional Additional data to update with (Can be NULL) + * \param add_len Length of additional data + * + * \return 0 if successful, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +int ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ); + +/** + * \brief CTR_DRBG generate random + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \param p_rng CTR_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * + * \return 0 if successful, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +int ctr_drbg_random( void *p_rng, + unsigned char *output, size_t output_len ); + +#if defined(POLARSSL_FS_IO) +/** + * \brief Write a seed file + * + * \param path Name of the file + * + * \return 0 if successful, 1 on file error, or + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int ctr_drbg_write_seed_file( ctr_drbg_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance + * + * \param path Name of the file + * + * \return 0 if successful, 1 on file error, + * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG + */ +int ctr_drbg_update_seed_file( ctr_drbg_context *ctx, const char *path ); +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int ctr_drbg_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* ctr_drbg.h */ diff --git a/src/libpolarssl/debug.c b/src/libpolarssl/debug.c new file mode 100644 index 0000000..414251e --- /dev/null +++ b/src/libpolarssl/debug.c @@ -0,0 +1,238 @@ +/* + * Debugging routines + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_DEBUG_C) + +#include "debug.h" + +#include +#include + +#if defined _MSC_VER && !defined snprintf +#define snprintf _snprintf +#endif + +#if defined _MSC_VER && !defined vsnprintf +#define vsnprintf _vsnprintf +#endif + +char *debug_fmt( const char *format, ... ) +{ + va_list argp; + static char str[512]; + int maxlen = sizeof( str ) - 1; + + va_start( argp, format ); + vsnprintf( str, maxlen, format, argp ); + va_end( argp ); + + str[maxlen] = '\0'; + return( str ); +} + +void debug_print_msg( const ssl_context *ssl, int level, + const char *file, int line, const char *text ) +{ + char str[512]; + int maxlen = sizeof( str ) - 1; + + if( ssl->f_dbg == NULL ) + return; + + snprintf( str, maxlen, "%s(%04d): %s\n", file, line, text ); + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); +} + +void debug_print_ret( const ssl_context *ssl, int level, + const char *file, int line, + const char *text, int ret ) +{ + char str[512]; + int maxlen = sizeof( str ) - 1; + + if( ssl->f_dbg == NULL ) + return; + + snprintf( str, maxlen, "%s(%04d): %s() returned %d (0x%x)\n", + file, line, text, ret, ret ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); +} + +void debug_print_buf( const ssl_context *ssl, int level, + const char *file, int line, const char *text, + unsigned char *buf, size_t len ) +{ + char str[512]; + size_t i, maxlen = sizeof( str ) - 1; + + if( ssl->f_dbg == NULL ) + return; + + snprintf( str, maxlen, "%s(%04d): dumping '%s' (%d bytes)\n", + file, line, text, (unsigned int) len ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + + for( i = 0; i < len; i++ ) + { + if( i >= 4096 ) + break; + + if( i % 16 == 0 ) + { + if( i > 0 ) + ssl->f_dbg( ssl->p_dbg, level, "\n" ); + + snprintf( str, maxlen, "%s(%04d): %04x: ", file, line, + (unsigned int) i ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + } + + snprintf( str, maxlen, " %02x", (unsigned int) buf[i] ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + } + + if( len > 0 ) + ssl->f_dbg( ssl->p_dbg, level, "\n" ); +} + +void debug_print_mpi( const ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mpi *X ) +{ + char str[512]; + int j, k, maxlen = sizeof( str ) - 1, zeros = 1; + size_t i, n; + + if( ssl->f_dbg == NULL || X == NULL ) + return; + + for( n = X->n - 1; n > 0; n-- ) + if( X->p[n] != 0 ) + break; + + for( j = ( sizeof(t_uint) << 3 ) - 1; j >= 0; j-- ) + if( ( ( X->p[n] >> j ) & 1 ) != 0 ) + break; + + snprintf( str, maxlen, "%s(%04d): value of '%s' (%d bits) is:\n", + file, line, text, + (int) ( ( n * ( sizeof(t_uint) << 3 ) ) + j + 1 ) ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + + for( i = n + 1, j = 0; i > 0; i-- ) + { + if( zeros && X->p[i - 1] == 0 ) + continue; + + for( k = sizeof( t_uint ) - 1; k >= 0; k-- ) + { + if( zeros && ( ( X->p[i - 1] >> (k << 3) ) & 0xFF ) == 0 ) + continue; + else + zeros = 0; + + if( j % 16 == 0 ) + { + if( j > 0 ) + ssl->f_dbg( ssl->p_dbg, level, "\n" ); + + snprintf( str, maxlen, "%s(%04d): ", file, line ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + } + + snprintf( str, maxlen, " %02x", (unsigned int) + ( X->p[i - 1] >> (k << 3) ) & 0xFF ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + + j++; + } + + } + + if( zeros == 1 ) + { + snprintf( str, maxlen, "%s(%04d): ", file, line ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + ssl->f_dbg( ssl->p_dbg, level, " 00" ); + } + + ssl->f_dbg( ssl->p_dbg, level, "\n" ); +} + +void debug_print_crt( const ssl_context *ssl, int level, + const char *file, int line, + const char *text, const x509_cert *crt ) +{ + char str[1024], prefix[64]; + int i = 0, maxlen = sizeof( prefix ) - 1; + + if( ssl->f_dbg == NULL || crt == NULL ) + return; + + snprintf( prefix, maxlen, "%s(%04d): ", file, line ); + prefix[maxlen] = '\0'; + maxlen = sizeof( str ) - 1; + + while( crt != NULL ) + { + char buf[1024]; + x509parse_cert_info( buf, sizeof( buf ) - 1, prefix, crt ); + + snprintf( str, maxlen, "%s(%04d): %s #%d:\n%s", + file, line, text, ++i, buf ); + + str[maxlen] = '\0'; + ssl->f_dbg( ssl->p_dbg, level, str ); + + debug_print_mpi( ssl, level, file, line, + "crt->rsa.N", &crt->rsa.N ); + + debug_print_mpi( ssl, level, file, line, + "crt->rsa.E", &crt->rsa.E ); + + crt = crt->next; + } +} + +#endif diff --git a/src/libpolarssl/debug.h b/src/libpolarssl/debug.h new file mode 100644 index 0000000..511e926 --- /dev/null +++ b/src/libpolarssl/debug.h @@ -0,0 +1,89 @@ +/** + * \file debug.h + * + * \brief Debug functions + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_DEBUG_H +#define POLARSSL_DEBUG_H + +#include "config.h" +#include "ssl.h" + +#if defined(POLARSSL_DEBUG_C) + +#define SSL_DEBUG_MSG( level, args ) \ + debug_print_msg( ssl, level, __FILE__, __LINE__, debug_fmt args ); + +#define SSL_DEBUG_RET( level, text, ret ) \ + debug_print_ret( ssl, level, __FILE__, __LINE__, text, ret ); + +#define SSL_DEBUG_BUF( level, text, buf, len ) \ + debug_print_buf( ssl, level, __FILE__, __LINE__, text, buf, len ); + +#define SSL_DEBUG_MPI( level, text, X ) \ + debug_print_mpi( ssl, level, __FILE__, __LINE__, text, X ); + +#define SSL_DEBUG_CRT( level, text, crt ) \ + debug_print_crt( ssl, level, __FILE__, __LINE__, text, crt ); + +#else + +#define SSL_DEBUG_MSG( level, args ) do { } while( 0 ) +#define SSL_DEBUG_RET( level, text, ret ) do { } while( 0 ) +#define SSL_DEBUG_BUF( level, text, buf, len ) do { } while( 0 ) +#define SSL_DEBUG_MPI( level, text, X ) do { } while( 0 ) +#define SSL_DEBUG_CRT( level, text, crt ) do { } while( 0 ) + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +char *debug_fmt( const char *format, ... ); + +void debug_print_msg( const ssl_context *ssl, int level, + const char *file, int line, const char *text ); + +void debug_print_ret( const ssl_context *ssl, int level, + const char *file, int line, + const char *text, int ret ); + +void debug_print_buf( const ssl_context *ssl, int level, + const char *file, int line, const char *text, + unsigned char *buf, size_t len ); + +void debug_print_mpi( const ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mpi *X ); + +void debug_print_crt( const ssl_context *ssl, int level, + const char *file, int line, + const char *text, const x509_cert *crt ); + +#ifdef __cplusplus +} +#endif + +#endif /* debug.h */ diff --git a/src/libpolarssl/des.c b/src/libpolarssl/des.c new file mode 100644 index 0000000..1aea4f5 --- /dev/null +++ b/src/libpolarssl/des.c @@ -0,0 +1,997 @@ +/* + * FIPS-46-3 compliant Triple-DES implementation + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * DES, on which TDES is based, was originally designed by Horst Feistel + * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). + * + * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf + */ + +#include "config.h" + +#if defined(POLARSSL_DES_C) + +#include "des.h" + +#if !defined(POLARSSL_DES_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Expanded DES S-boxes + */ +static const uint32_t SB1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static const uint32_t SB2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static const uint32_t SB3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static const uint32_t SB4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static const uint32_t SB5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static const uint32_t SB6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static const uint32_t SB7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static const uint32_t SB8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + +/* + * PC1: left and right halves bit-swap + */ +static const uint32_t LHs[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const uint32_t RHs[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + +/* + * Initial Permutation macro + */ +#define DES_IP(X,Y) \ +{ \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ + X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ +} + +/* + * Final Permutation macro + */ +#define DES_FP(X,Y) \ +{ \ + X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ + Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ +} + +/* + * DES round macro + */ +#define DES_ROUND(X,Y) \ +{ \ + T = *SK++ ^ X; \ + Y ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ ((X << 28) | (X >> 4)); \ + Y ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ +} + +#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 0; } + +static const unsigned char odd_parity_table[128] = { 1, 2, 4, 7, 8, + 11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38, 41, 42, 44, + 47, 49, 50, 52, 55, 56, 59, 61, 62, 64, 67, 69, 70, 73, 74, 76, 79, 81, + 82, 84, 87, 88, 91, 93, 94, 97, 98, 100, 103, 104, 107, 109, 110, 112, + 115, 117, 118, 121, 122, 124, 127, 128, 131, 133, 134, 137, 138, 140, + 143, 145, 146, 148, 151, 152, 155, 157, 158, 161, 162, 164, 167, 168, + 171, 173, 174, 176, 179, 181, 182, 185, 186, 188, 191, 193, 194, 196, + 199, 200, 203, 205, 206, 208, 211, 213, 214, 217, 218, 220, 223, 224, + 227, 229, 230, 233, 234, 236, 239, 241, 242, 244, 247, 248, 251, 253, + 254 }; + +void des_key_set_parity( unsigned char key[DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < DES_KEY_SIZE; i++ ) + key[i] = odd_parity_table[key[i] / 2]; +} + +/* + * Check the given key's parity, returns 1 on failure, 0 on SUCCESS + */ +int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < DES_KEY_SIZE; i++ ) + if ( key[i] != odd_parity_table[key[i] / 2] ) + return( 1 ); + + return( 0 ); +} + +/* + * Table of weak and semi-weak keys + * + * Source: http://en.wikipedia.org/wiki/Weak_key + * + * Weak: + * Alternating ones + zeros (0x0101010101010101) + * Alternating 'F' + 'E' (0xFEFEFEFEFEFEFEFE) + * '0xE0E0E0E0F1F1F1F1' + * '0x1F1F1F1F0E0E0E0E' + * + * Semi-weak: + * 0x011F011F010E010E and 0x1F011F010E010E01 + * 0x01E001E001F101F1 and 0xE001E001F101F101 + * 0x01FE01FE01FE01FE and 0xFE01FE01FE01FE01 + * 0x1FE01FE00EF10EF1 and 0xE01FE01FF10EF10E + * 0x1FFE1FFE0EFE0EFE and 0xFE1FFE1FFE0EFE0E + * 0xE0FEE0FEF1FEF1FE and 0xFEE0FEE0FEF1FEF1 + * + */ + +#define WEAK_KEY_COUNT 16 + +static const unsigned char weak_key_table[WEAK_KEY_COUNT][DES_KEY_SIZE] = +{ + { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE }, + { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E }, + { 0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1 }, + + { 0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E }, + { 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01 }, + { 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1 }, + { 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01 }, + { 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE }, + { 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01 }, + { 0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1 }, + { 0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E }, + { 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE }, + { 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E }, + { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE }, + { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1 } +}; + +int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < WEAK_KEY_COUNT; i++ ) + if( memcmp( weak_key_table[i], key, DES_KEY_SIZE) == 0) + return( 1 ); + + return( 0 ); +} + +static void des_setkey( uint32_t SK[32], const unsigned char key[DES_KEY_SIZE] ) +{ + int i; + uint32_t X, Y, T; + + GET_UINT32_BE( X, key, 0 ); + GET_UINT32_BE( Y, key, 4 ); + + /* + * Permuted Choice 1 + */ + T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); + T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); + + X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) + | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) + | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) + | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); + + Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) + | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) + | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) + | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); + + X &= 0x0FFFFFFF; + Y &= 0x0FFFFFFF; + + /* + * calculate subkeys + */ + for( i = 0; i < 16; i++ ) + { + if( i < 2 || i == 8 || i == 15 ) + { + X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; + Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; + } + else + { + X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; + Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; + } + + *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) + | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) + | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) + | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) + | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) + | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) + | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) + | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) + | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) + | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) + | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); + + *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) + | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) + | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) + | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) + | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) + | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) + | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) + | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) + | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) + | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) + | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); + } +} + +/* + * DES key schedule (56-bit, encryption) + */ +int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ) +{ + des_setkey( ctx->sk, key ); + + return( 0 ); +} + +/* + * DES key schedule (56-bit, decryption) + */ +int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ) +{ + int i; + + des_setkey( ctx->sk, key ); + + for( i = 0; i < 16; i += 2 ) + { + SWAP( ctx->sk[i ], ctx->sk[30 - i] ); + SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); + } + + return( 0 ); +} + +static void des3_set2key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[DES_KEY_SIZE*2] ) +{ + int i; + + des_setkey( esk, key ); + des_setkey( dsk + 32, key + 8 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[30 - i]; + dsk[i + 1] = esk[31 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + esk[i + 64] = esk[i ]; + esk[i + 65] = esk[i + 1]; + + dsk[i + 64] = dsk[i ]; + dsk[i + 65] = dsk[i + 1]; + } +} + +/* + * Triple-DES key schedule (112-bit, encryption) + */ +int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( ctx->sk, sk, key ); + memset( sk, 0, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (112-bit, decryption) + */ +int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( sk, ctx->sk, key ); + memset( sk, 0, sizeof( sk ) ); + + return( 0 ); +} + +static void des3_set3key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[24] ) +{ + int i; + + des_setkey( esk, key ); + des_setkey( dsk + 32, key + 8 ); + des_setkey( esk + 64, key + 16 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[94 - i]; + dsk[i + 1] = esk[95 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + dsk[i + 64] = esk[30 - i]; + dsk[i + 65] = esk[31 - i]; + } +} + +/* + * Triple-DES key schedule (168-bit, encryption) + */ +int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( ctx->sk, sk, key ); + memset( sk, 0, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (168-bit, decryption) + */ +int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( sk, ctx->sk, key ); + memset( sk, 0, sizeof( sk ) ); + + return( 0 ); +} + +/* + * DES-ECB block encryption/decryption + */ +int des_crypt_ecb( des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} + +/* + * DES-CBC buffer encryption/decryption + */ +int des_crypt_cbc( des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( POLARSSL_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + des_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + des_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} + +/* + * 3DES-ECB block encryption/decryption + */ +int des3_crypt_ecb( des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( X, Y ); + DES_ROUND( Y, X ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} + +/* + * 3DES-CBC buffer encryption/decryption + */ +int des3_crypt_cbc( des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( POLARSSL_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + des3_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + des3_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} + +#endif /* !POLARSSL_DES_ALT */ + +#if defined(POLARSSL_SELF_TEST) + +#include + +/* + * DES and 3DES test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip + */ +static const unsigned char des3_test_keys[24] = +{ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, + 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 +}; + +static const unsigned char des3_test_iv[8] = +{ + 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, +}; + +static const unsigned char des3_test_buf[8] = +{ + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 +}; + +static const unsigned char des3_test_ecb_dec[3][8] = +{ + { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D }, + { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB }, + { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A } +}; + +static const unsigned char des3_test_ecb_enc[3][8] = +{ + { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B }, + { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 }, + { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 } +}; + +static const unsigned char des3_test_cbc_dec[3][8] = +{ + { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 }, + { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 }, + { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C } +}; + +static const unsigned char des3_test_cbc_enc[3][8] = +{ + { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 }, + { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D }, + { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 } +}; + +/* + * Checkup routine + */ +int des_self_test( int verbose ) +{ + int i, j, u, v; + des_context ctx; + des3_context ctx3; + unsigned char key[24]; + unsigned char buf[8]; + unsigned char prv[8]; + unsigned char iv[8]; + + memset( key, 0, 24 ); + + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " DES%c-ECB-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + des_crypt_ecb( &ctx, buf, buf ); + else + des3_crypt_ecb( &ctx3, buf, buf ); + } + + if( ( v == DES_DECRYPT && + memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) || + ( v != DES_DECRYPT && + memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + printf( " DES%c-CBC-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, des3_test_iv, 8 ); + memcpy( prv, des3_test_iv, 8 ); + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + if( v == DES_DECRYPT ) + { + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + } + } + else + { + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[8]; + + if( u == 0 ) + des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + + memcpy( tmp, prv, 8 ); + memcpy( prv, buf, 8 ); + memcpy( buf, tmp, 8 ); + } + + memcpy( buf, prv, 8 ); + } + + if( ( v == DES_DECRYPT && + memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) || + ( v != DES_DECRYPT && + memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/des.h b/src/libpolarssl/des.h new file mode 100644 index 0000000..d78b568 --- /dev/null +++ b/src/libpolarssl/des.h @@ -0,0 +1,252 @@ +/** + * \file des.h + * + * \brief DES block cipher + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_DES_H +#define POLARSSL_DES_H + +#include "config.h" + +#include + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +#define POLARSSL_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */ + +#define DES_KEY_SIZE 8 + +#if !defined(POLARSSL_DES_ALT) +// Regular implementation +// + +/** + * \brief DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + uint32_t sk[32]; /*!< DES subkeys */ +} +des_context; + +/** + * \brief Triple-DES context structure + */ +typedef struct +{ + int mode; /*!< encrypt/decrypt */ + uint32_t sk[96]; /*!< 3DES subkeys */ +} +des3_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Set key parity on the given key to odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + */ +void des_key_set_parity( unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief Check that key parity on the given key is odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + * + * \return 0 is parity was ok, 1 if parity was not correct. + */ +int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief Check that key is not a weak or semi-weak DES key + * + * \param key 8-byte secret key + * + * \return 0 if no weak key was found, 1 if a weak key was identified. + */ +int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, encryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + */ +int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, decryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + */ +int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ); + +/** + * \brief Triple-DES key schedule (112-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (112-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (168-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ); + +/** + * \brief Triple-DES key schedule (168-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ); + +/** + * \brief DES-ECB block encryption/decryption + * + * \param ctx DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int des_crypt_ecb( des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +/** + * \brief DES-CBC buffer encryption/decryption + * + * \param ctx DES context + * \param mode DES_ENCRYPT or DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + */ +int des_crypt_cbc( des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief 3DES-ECB block encryption/decryption + * + * \param ctx 3DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int des3_crypt_ecb( des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +/** + * \brief 3DES-CBC buffer encryption/decryption + * + * \param ctx 3DES context + * \param mode DES_ENCRYPT or DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or POLARSSL_ERR_DES_INVALID_INPUT_LENGTH + */ +int des3_crypt_cbc( des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_DES_ALT */ +#include "des_alt.h" +#endif /* POLARSSL_DES_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int des_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* des.h */ diff --git a/src/libpolarssl/dhm.c b/src/libpolarssl/dhm.c new file mode 100644 index 0000000..83e9bd3 --- /dev/null +++ b/src/libpolarssl/dhm.c @@ -0,0 +1,302 @@ +/* + * Diffie-Hellman-Merkle key exchange + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * Reference: + * + * http://www.cacr.math.uwaterloo.ca/hac/ (chapter 12) + */ + +#include "config.h" + +#if defined(POLARSSL_DHM_C) + +#include "dhm.h" + +/* + * helper to validate the mpi size and import it + */ +static int dhm_read_bignum( mpi *X, + unsigned char **p, + const unsigned char *end ) +{ + int ret, n; + + if( end - *p < 2 ) + return( POLARSSL_ERR_DHM_BAD_INPUT_DATA ); + + n = ( (*p)[0] << 8 ) | (*p)[1]; + (*p) += 2; + + if( (int)( end - *p ) < n ) + return( POLARSSL_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = mpi_read_binary( X, *p, n ) ) != 0 ) + return( POLARSSL_ERR_DHM_READ_PARAMS_FAILED + ret ); + + (*p) += n; + + return( 0 ); +} + +/* + * Verify sanity of parameter with regards to P + * + * Parameter should be: 2 <= public_param <= P - 2 + * + * For more information on the attack, see: + * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf + * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643 + */ +static int dhm_check_range( const mpi *param, const mpi *P ) +{ + mpi L, U; + int ret = POLARSSL_ERR_DHM_BAD_INPUT_DATA; + + mpi_init( &L ); mpi_init( &U ); + mpi_lset( &L, 2 ); + mpi_sub_int( &U, P, 2 ); + + if( mpi_cmp_mpi( param, &L ) >= 0 && + mpi_cmp_mpi( param, &U ) <= 0 ) + { + ret = 0; + } + + mpi_free( &L ); mpi_free( &U ); + + return( ret ); +} + +/* + * Parse the ServerKeyExchange parameters + */ +int dhm_read_params( dhm_context *ctx, + unsigned char **p, + const unsigned char *end ) +{ + int ret; + + memset( ctx, 0, sizeof( dhm_context ) ); + + if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 || + ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 || + ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 ) + return( ret ); + + if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) + return( ret ); + + ctx->len = mpi_size( &ctx->P ); + + if( end - *p < 2 ) + return( POLARSSL_ERR_DHM_BAD_INPUT_DATA ); + + return( 0 ); +} + +/* + * Setup and write the ServerKeyExchange parameters + */ +int dhm_make_params( dhm_context *ctx, int x_size, + unsigned char *output, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count = 0; + size_t n1, n2, n3; + unsigned char *p; + + if( mpi_cmp_int( &ctx->P, 0 ) == 0 ) + return( POLARSSL_ERR_DHM_BAD_INPUT_DATA ); + + /* + * Generate X as large as possible ( < P ) + */ + do + { + mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ); + + while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) + mpi_shift_r( &ctx->X, 1 ); + + if( count++ > 10 ) + return( POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED ); + } + while( dhm_check_range( &ctx->X, &ctx->P ) != 0 ); + + /* + * Calculate GX = G^X mod P + */ + MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, + &ctx->P , &ctx->RP ) ); + + if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) + return( ret ); + + /* + * export P, G, GX + */ +#define DHM_MPI_EXPORT(X,n) \ + MPI_CHK( mpi_write_binary( X, p + 2, n ) ); \ + *p++ = (unsigned char)( n >> 8 ); \ + *p++ = (unsigned char)( n ); p += n; + + n1 = mpi_size( &ctx->P ); + n2 = mpi_size( &ctx->G ); + n3 = mpi_size( &ctx->GX ); + + p = output; + DHM_MPI_EXPORT( &ctx->P , n1 ); + DHM_MPI_EXPORT( &ctx->G , n2 ); + DHM_MPI_EXPORT( &ctx->GX, n3 ); + + *olen = p - output; + + ctx->len = n1; + +cleanup: + + if( ret != 0 ) + return( POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED + ret ); + + return( 0 ); +} + +/* + * Import the peer's public value G^Y + */ +int dhm_read_public( dhm_context *ctx, + const unsigned char *input, size_t ilen ) +{ + int ret; + + if( ctx == NULL || ilen < 1 || ilen > ctx->len ) + return( POLARSSL_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 ) + return( POLARSSL_ERR_DHM_READ_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Create own private value X and export G^X + */ +int dhm_make_public( dhm_context *ctx, int x_size, + unsigned char *output, size_t olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count = 0; + + if( ctx == NULL || olen < 1 || olen > ctx->len ) + return( POLARSSL_ERR_DHM_BAD_INPUT_DATA ); + + if( mpi_cmp_int( &ctx->P, 0 ) == 0 ) + return( POLARSSL_ERR_DHM_BAD_INPUT_DATA ); + + /* + * generate X and calculate GX = G^X mod P + */ + do + { + mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ); + + while( mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) + mpi_shift_r( &ctx->X, 1 ); + + if( count++ > 10 ) + return( POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED ); + } + while( dhm_check_range( &ctx->X, &ctx->P ) != 0 ); + + MPI_CHK( mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, + &ctx->P , &ctx->RP ) ); + + if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) + return( ret ); + + MPI_CHK( mpi_write_binary( &ctx->GX, output, olen ) ); + +cleanup: + + if( ret != 0 ) + return( POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Derive and export the shared secret (G^Y)^X mod P + */ +int dhm_calc_secret( dhm_context *ctx, + unsigned char *output, size_t *olen ) +{ + int ret; + + if( ctx == NULL || *olen < ctx->len ) + return( POLARSSL_ERR_DHM_BAD_INPUT_DATA ); + + MPI_CHK( mpi_exp_mod( &ctx->K, &ctx->GY, &ctx->X, + &ctx->P, &ctx->RP ) ); + + if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) + return( ret ); + + *olen = mpi_size( &ctx->K ); + + MPI_CHK( mpi_write_binary( &ctx->K, output, *olen ) ); + +cleanup: + + if( ret != 0 ) + return( POLARSSL_ERR_DHM_CALC_SECRET_FAILED + ret ); + + return( 0 ); +} + +/* + * Free the components of a DHM key + */ +void dhm_free( dhm_context *ctx ) +{ + mpi_free( &ctx->RP ); mpi_free( &ctx->K ); mpi_free( &ctx->GY ); + mpi_free( &ctx->GX ); mpi_free( &ctx->X ); mpi_free( &ctx->G ); + mpi_free( &ctx->P ); +} + +#if defined(POLARSSL_SELF_TEST) + +/* + * Checkup routine + */ +int dhm_self_test( int verbose ) +{ + return( verbose++ ); +} + +#endif + +#endif diff --git a/src/libpolarssl/dhm.h b/src/libpolarssl/dhm.h new file mode 100644 index 0000000..48d9268 --- /dev/null +++ b/src/libpolarssl/dhm.h @@ -0,0 +1,244 @@ +/** + * \file dhm.h + * + * \brief Diffie-Hellman-Merkle key exchange + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_DHM_H +#define POLARSSL_DHM_H + +#include "bignum.h" + +/* + * DHM Error codes + */ +#define POLARSSL_ERR_DHM_BAD_INPUT_DATA -0x3080 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_DHM_READ_PARAMS_FAILED -0x3100 /**< Reading of the DHM parameters failed. */ +#define POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED -0x3180 /**< Making of the DHM parameters failed. */ +#define POLARSSL_ERR_DHM_READ_PUBLIC_FAILED -0x3200 /**< Reading of the public values failed. */ +#define POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED -0x3280 /**< Making of the public value failed. */ +#define POLARSSL_ERR_DHM_CALC_SECRET_FAILED -0x3300 /**< Calculation of the DHM secret failed. */ + +/** + * RFC 3526 defines a number of standardized Diffie-Hellman groups + * for IKE. + * RFC 5114 defines a number of standardized Diffie-Hellman groups + * that can be used. + * + * Some are included here for convenience. + * + * Included are: + * RFC 3526 3. 2048-bit MODP Group + * RFC 3526 4. 3072-bit MODP Group + * RFC 5114 2.1. 1024-bit MODP Group with 160-bit Prime Order Subgroup + * RFC 5114 2.2. 2048-bit MODP Group with 224-bit Prime Order Subgroup + */ +#define POLARSSL_DHM_RFC3526_MODP_2048_P \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AACAA68FFFFFFFFFFFFFFFF" + +#define POLARSSL_DHM_RFC3526_MODP_2048_G "02" + +#define POLARSSL_DHM_RFC3526_MODP_3072_P \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF" + +#define POLARSSL_DHM_RFC3526_MODP_3072_G "02" + +#define POLARSSL_DHM_RFC5114_MODP_1024_P \ + "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C6" \ + "9A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C0" \ + "13ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD70" \ + "98488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0" \ + "A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708" \ + "DF1FB2BC2E4A4371" + +#define POLARSSL_DHM_RFC5114_MODP_1024_G \ + "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507F" \ + "D6406CFF14266D31266FEA1E5C41564B777E690F5504F213" \ + "160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1" \ + "909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28A" \ + "D662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24" \ + "855E6EEB22B3B2E5" + +#define POLARSSL_DHM_RFC5114_MODP_2048_P \ + "AD107E1E9123A9D0D660FAA79559C51FA20D64E5683B9FD1" \ + "B54B1597B61D0A75E6FA141DF95A56DBAF9A3C407BA1DF15" \ + "EB3D688A309C180E1DE6B85A1274A0A66D3F8152AD6AC212" \ + "9037C9EDEFDA4DF8D91E8FEF55B7394B7AD5B7D0B6C12207" \ + "C9F98D11ED34DBF6C6BA0B2C8BBC27BE6A00E0A0B9C49708" \ + "B3BF8A317091883681286130BC8985DB1602E714415D9330" \ + "278273C7DE31EFDC7310F7121FD5A07415987D9ADC0A486D" \ + "CDF93ACC44328387315D75E198C641A480CD86A1B9E587E8" \ + "BE60E69CC928B2B9C52172E413042E9B23F10B0E16E79763" \ + "C9B53DCF4BA80A29E3FB73C16B8E75B97EF363E2FFA31F71" \ + "CF9DE5384E71B81C0AC4DFFE0C10E64F" + +#define POLARSSL_DHM_RFC5114_MODP_2048_G \ + "AC4032EF4F2D9AE39DF30B5C8FFDAC506CDEBE7B89998CAF"\ + "74866A08CFE4FFE3A6824A4E10B9A6F0DD921F01A70C4AFA"\ + "AB739D7700C29F52C57DB17C620A8652BE5E9001A8D66AD7"\ + "C17669101999024AF4D027275AC1348BB8A762D0521BC98A"\ + "E247150422EA1ED409939D54DA7460CDB5F6C6B250717CBE"\ + "F180EB34118E98D119529A45D6F834566E3025E316A330EF"\ + "BB77A86F0C1AB15B051AE3D428C8F8ACB70A8137150B8EEB"\ + "10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381"\ + "B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269"\ + "EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC0179"\ + "81BC087F2A7065B384B890D3191F2BFA" + +/** + * \brief DHM context structure + */ +typedef struct +{ + size_t len; /*!< size(P) in chars */ + mpi P; /*!< prime modulus */ + mpi G; /*!< generator */ + mpi X; /*!< secret value */ + mpi GX; /*!< self = G^X mod P */ + mpi GY; /*!< peer = G^Y mod P */ + mpi K; /*!< key = GY^X mod P */ + mpi RP; /*!< cached R^2 mod P */ +} +dhm_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Parse the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param p &(start of input buffer) + * \param end end of buffer + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_read_params( dhm_context *ctx, + unsigned char **p, + const unsigned char *end ); + +/** + * \brief Setup and write the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param x_size private value size in bytes + * \param output destination buffer + * \param olen number of chars written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note This function assumes that ctx->P and ctx->G + * have already been properly set (for example + * using mpi_read_string or mpi_read_binary). + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_make_params( dhm_context *ctx, int x_size, + unsigned char *output, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Import the peer's public value G^Y + * + * \param ctx DHM context + * \param input input buffer + * \param ilen size of buffer + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_read_public( dhm_context *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief Create own private value X and export G^X + * + * \param ctx DHM context + * \param x_size private value size in bytes + * \param output destination buffer + * \param olen must be equal to ctx->P.len + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_make_public( dhm_context *ctx, int x_size, + unsigned char *output, size_t olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Derive and export the shared secret (G^Y)^X mod P + * + * \param ctx DHM context + * \param output destination buffer + * \param olen number of chars written + * + * \return 0 if successful, or an POLARSSL_ERR_DHM_XXX error code + */ +int dhm_calc_secret( dhm_context *ctx, + unsigned char *output, size_t *olen ); + +/** + * \brief Free the components of a DHM key + */ +void dhm_free( dhm_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int dhm_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libpolarssl/entropy.c b/src/libpolarssl/entropy.c new file mode 100644 index 0000000..d99623a --- /dev/null +++ b/src/libpolarssl/entropy.c @@ -0,0 +1,204 @@ +/* + * Entropy accumulator implementation + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_ENTROPY_C) + +#include "entropy.h" +#include "entropy_poll.h" + +#if defined(POLARSSL_HAVEGE_C) +#include "havege.h" +#endif + +#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ + +void entropy_init( entropy_context *ctx ) +{ + memset( ctx, 0, sizeof(entropy_context) ); + + sha4_starts( &ctx->accumulator, 0 ); +#if defined(POLARSSL_HAVEGE_C) + havege_init( &ctx->havege_data ); +#endif + +#if !defined(POLARSSL_NO_DEFAULT_ENTROPY_SOURCES) +#if !defined(POLARSSL_NO_PLATFORM_ENTROPY) + entropy_add_source( ctx, platform_entropy_poll, NULL, + ENTROPY_MIN_PLATFORM ); +#endif +#if defined(POLARSSL_TIMING_C) + entropy_add_source( ctx, hardclock_poll, NULL, ENTROPY_MIN_HARDCLOCK ); +#endif +#if defined(POLARSSL_HAVEGE_C) + entropy_add_source( ctx, havege_poll, &ctx->havege_data, + ENTROPY_MIN_HAVEGE ); +#endif +#endif /* POLARSSL_NO_DEFAULT_ENTROPY_SOURCES */ +} + +int entropy_add_source( entropy_context *ctx, + f_source_ptr f_source, void *p_source, + size_t threshold ) +{ + int index = ctx->source_count; + + if( index >= ENTROPY_MAX_SOURCES ) + return( POLARSSL_ERR_ENTROPY_MAX_SOURCES ); + + ctx->source[index].f_source = f_source; + ctx->source[index].p_source = p_source; + ctx->source[index].threshold = threshold; + + ctx->source_count++; + + return( 0 ); +} + +/* + * Entropy accumulator update + */ +int entropy_update( entropy_context *ctx, unsigned char source_id, + const unsigned char *data, size_t len ) +{ + unsigned char header[2]; + unsigned char tmp[ENTROPY_BLOCK_SIZE]; + size_t use_len = len; + const unsigned char *p = data; + + if( use_len > ENTROPY_BLOCK_SIZE ) + { + sha4( data, len, tmp, 0 ); + + p = tmp; + use_len = ENTROPY_BLOCK_SIZE; + } + + header[0] = source_id; + header[1] = use_len & 0xFF; + + sha4_update( &ctx->accumulator, header, 2 ); + sha4_update( &ctx->accumulator, p, use_len ); + + return( 0 ); +} + +int entropy_update_manual( entropy_context *ctx, + const unsigned char *data, size_t len ) +{ + return entropy_update( ctx, ENTROPY_SOURCE_MANUAL, data, len ); +} + +/* + * Run through the different sources to add entropy to our accumulator + */ +int entropy_gather( entropy_context *ctx ) +{ + int ret, i; + unsigned char buf[ENTROPY_MAX_GATHER]; + size_t olen; + + if( ctx->source_count == 0 ) + return( POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED ); + + /* + * Run through our entropy sources + */ + for( i = 0; i < ctx->source_count; i++ ) + { + olen = 0; + if ( ( ret = ctx->source[i].f_source( ctx->source[i].p_source, + buf, ENTROPY_MAX_GATHER, &olen ) ) != 0 ) + { + return( ret ); + } + + /* + * Add if we actually gathered something + */ + if( olen > 0 ) + { + entropy_update( ctx, (unsigned char) i, buf, olen ); + ctx->source[i].size += olen; + } + } + + return( 0 ); +} + +int entropy_func( void *data, unsigned char *output, size_t len ) +{ + int ret, count = 0, i, reached; + entropy_context *ctx = (entropy_context *) data; + unsigned char buf[ENTROPY_BLOCK_SIZE]; + + if( len > ENTROPY_BLOCK_SIZE ) + return( POLARSSL_ERR_ENTROPY_SOURCE_FAILED ); + + /* + * Always gather extra entropy before a call + */ + do + { + if( count++ > ENTROPY_MAX_LOOP ) + return( POLARSSL_ERR_ENTROPY_SOURCE_FAILED ); + + if( ( ret = entropy_gather( ctx ) ) != 0 ) + return( ret ); + + reached = 0; + + for( i = 0; i < ctx->source_count; i++ ) + if( ctx->source[i].size >= ctx->source[i].threshold ) + reached++; + } + while( reached != ctx->source_count ); + + memset( buf, 0, ENTROPY_BLOCK_SIZE ); + + sha4_finish( &ctx->accumulator, buf ); + + /* + * Perform second SHA-512 on entropy + */ + sha4( buf, ENTROPY_BLOCK_SIZE, buf, 0 ); + + /* + * Reset accumulator and counters and recycle existing entropy + */ + memset( &ctx->accumulator, 0, sizeof( sha4_context ) ); + sha4_starts( &ctx->accumulator, 0 ); + sha4_update( &ctx->accumulator, buf, ENTROPY_BLOCK_SIZE ); + + for( i = 0; i < ctx->source_count; i++ ) + ctx->source[i].size = 0; + + memcpy( output, buf, len ); + + return( 0 ); +} + +#endif diff --git a/src/libpolarssl/entropy.h b/src/libpolarssl/entropy.h new file mode 100644 index 0000000..039f5cd --- /dev/null +++ b/src/libpolarssl/entropy.h @@ -0,0 +1,153 @@ +/** + * \file entropy.h + * + * \brief Entropy accumulator implementation + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ENTROPY_H +#define POLARSSL_ENTROPY_H + +#include + +#include "config.h" + +#include "sha4.h" +#if defined(POLARSSL_HAVEGE_C) +#include "havege.h" +#endif + +#define POLARSSL_ERR_ENTROPY_SOURCE_FAILED -0x003C /**< Critical entropy source failure. */ +#define POLARSSL_ERR_ENTROPY_MAX_SOURCES -0x003E /**< No more sources can be added. */ +#define POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED -0x0040 /**< No sources have been added to poll. */ + +#if !defined(POLARSSL_CONFIG_OPTIONS) +#define ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +#define ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +#endif /* !POLARSSL_CONFIG_OPTIONS */ + +#define ENTROPY_BLOCK_SIZE 64 /**< Block size of entropy accumulator (SHA-512) */ + +#define ENTROPY_SOURCE_MANUAL ENTROPY_MAX_SOURCES + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Entropy poll callback pointer + * + * \param data Callback-specific data pointer + * \param output Data to fill + * \param len Maximum size to provide + * \param olen The actual amount of bytes put into the buffer (Can be 0) + * + * \return 0 if no critical failures occurred, + * POLARSSL_ERR_ENTROPY_SOURCE_FAILED otherwise + */ +typedef int (*f_source_ptr)(void *, unsigned char *, size_t, size_t *); + +/** + * \brief Entropy source state + */ +typedef struct +{ + f_source_ptr f_source; /**< The entropy source callback */ + void * p_source; /**< The callback data pointer */ + size_t size; /**< Amount received */ + size_t threshold; /**< Minimum level required before release */ +} +source_state; + +/** + * \brief Entropy context structure + */ +typedef struct +{ + sha4_context accumulator; + int source_count; + source_state source[ENTROPY_MAX_SOURCES]; +#if defined(POLARSSL_HAVEGE_C) + havege_state havege_data; +#endif +} +entropy_context; + +/** + * \brief Initialize the context + * + * \param ctx Entropy context to initialize + */ +void entropy_init( entropy_context *ctx ); + +/** + * \brief Adds an entropy source to poll + * + * \param ctx Entropy context + * \param f_source Entropy function + * \param p_source Function data + * \param threshold Minimum required from source before entropy is released + * ( with entropy_func() ) + * + * \return 0 if successful or POLARSSL_ERR_ENTROPY_MAX_SOURCES + */ +int entropy_add_source( entropy_context *ctx, + f_source_ptr f_source, void *p_source, + size_t threshold ); + +/** + * \brief Trigger an extra gather poll for the accumulator + * + * \param ctx Entropy context + * + * \return 0 if successful, or POLARSSL_ERR_ENTROPY_SOURCE_FAILED + */ +int entropy_gather( entropy_context *ctx ); + +/** + * \brief Retrieve entropy from the accumulator (Max ENTROPY_BLOCK_SIZE) + * + * \param data Entropy context + * \param output Buffer to fill + * \param len Length of buffer + * + * \return 0 if successful, or POLARSSL_ERR_ENTROPY_SOURCE_FAILED + */ +int entropy_func( void *data, unsigned char *output, size_t len ); + +/** + * \brief Add data to the accumulator manually + * + * \param ctx Entropy context + * \param data Data to add + * \param len Length of data + * + * \return 0 if successful + */ +int entropy_update_manual( entropy_context *ctx, + const unsigned char *data, size_t len ); + +#ifdef __cplusplus +} +#endif + +#endif /* entropy.h */ diff --git a/src/libpolarssl/entropy_poll.c b/src/libpolarssl/entropy_poll.c new file mode 100644 index 0000000..040c1b0 --- /dev/null +++ b/src/libpolarssl/entropy_poll.c @@ -0,0 +1,136 @@ +/* + * Platform-specific and custom entropy polling functions + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_ENTROPY_C) + +#include "entropy.h" +#include "entropy_poll.h" + +#if defined(POLARSSL_TIMING_C) +#include "timing.h" +#endif +#if defined(POLARSSL_HAVEGE_C) +#include "havege.h" +#endif + +#if !defined(POLARSSL_NO_PLATFORM_ENTROPY) +#if defined(_WIN32) + +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0400 +#endif +#include +#include + +int platform_entropy_poll( void *data, unsigned char *output, size_t len, + size_t *olen ) +{ + HCRYPTPROV provider; + ((void) data); + *olen = 0; + + if( CryptAcquireContext( &provider, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) == FALSE ) + { + return POLARSSL_ERR_ENTROPY_SOURCE_FAILED; + } + + if( CryptGenRandom( provider, len, output ) == FALSE ) + return POLARSSL_ERR_ENTROPY_SOURCE_FAILED; + + CryptReleaseContext( provider, 0 ); + *olen = len; + + return( 0 ); +} +#else + +#include + +int platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + FILE *file; + size_t ret; + ((void) data); + + *olen = 0; + + file = fopen( "/dev/urandom", "rb" ); + if( file == NULL ) + return POLARSSL_ERR_ENTROPY_SOURCE_FAILED; + + ret = fread( output, 1, len, file ); + if( ret != len ) + { + fclose( file ); + return POLARSSL_ERR_ENTROPY_SOURCE_FAILED; + } + + fclose( file ); + *olen = len; + + return( 0 ); +} +#endif +#endif + +#if defined(POLARSSL_TIMING_C) +int hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + unsigned long timer = hardclock(); + ((void) data); + *olen = 0; + + if( len < sizeof(unsigned long) ) + return( 0 ); + + memcpy( output, &timer, sizeof(unsigned long) ); + *olen = sizeof(unsigned long); + + return( 0 ); +} +#endif + +#if defined(POLARSSL_HAVEGE_C) +int havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + havege_state *hs = (havege_state *) data; + *olen = 0; + + if( havege_random( hs, output, len ) != 0 ) + return POLARSSL_ERR_ENTROPY_SOURCE_FAILED; + + *olen = len; + + return( 0 ); +} +#endif + +#endif /* POLARSSL_ENTROPY_C */ diff --git a/src/libpolarssl/entropy_poll.h b/src/libpolarssl/entropy_poll.h new file mode 100644 index 0000000..0116598 --- /dev/null +++ b/src/libpolarssl/entropy_poll.h @@ -0,0 +1,75 @@ +/** + * \file entropy_poll.h + * + * \brief Platform-specific and custom entropy polling functions + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ENTROPY_POLL_H +#define POLARSSL_ENTROPY_POLL_H + +#include + +#include "config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Default thresholds for built-in sources + */ +#define ENTROPY_MIN_PLATFORM 128 /**< Minimum for platform source */ +#define ENTROPY_MIN_HAVEGE 128 /**< Minimum for HAVEGE */ +#define ENTROPY_MIN_HARDCLOCK 32 /**< Minimum for hardclock() */ + +#if !defined(POLARSSL_NO_PLATFORM_ENTROPY) +/** + * \brief Platform-specific entropy poll callback + */ +int platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(POLARSSL_HAVEGE_C) +/** + * \brief HAVEGE based entropy poll callback + * + * Requires an HAVEGE state as its data pointer. + */ +int havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(POLARSSL_TIMING_C) +/** + * \brief hardclock-based entropy poll callback + */ +int hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* entropy_poll.h */ diff --git a/src/libpolarssl/error.c b/src/libpolarssl/error.c new file mode 100644 index 0000000..05f0662 --- /dev/null +++ b/src/libpolarssl/error.c @@ -0,0 +1,612 @@ +/* + * Error message information + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_ERROR_C) + +#include "error.h" + +#if defined(POLARSSL_AES_C) +#include "aes.h" +#endif + +#if defined(POLARSSL_BASE64_C) +#include "base64.h" +#endif + +#if defined(POLARSSL_BIGNUM_C) +#include "bignum.h" +#endif + +#if defined(POLARSSL_BLOWFISH_C) +#include "blowfish.h" +#endif + +#if defined(POLARSSL_CAMELLIA_C) +#include "camellia.h" +#endif + +#if defined(POLARSSL_CIPHER_C) +#include "cipher.h" +#endif + +#if defined(POLARSSL_CTR_DRBG_C) +#include "ctr_drbg.h" +#endif + +#if defined(POLARSSL_DES_C) +#include "des.h" +#endif + +#if defined(POLARSSL_DHM_C) +#include "dhm.h" +#endif + +#if defined(POLARSSL_ENTROPY_C) +#include "entropy.h" +#endif + +#if defined(POLARSSL_GCM_C) +#include "gcm.h" +#endif + +#if defined(POLARSSL_MD_C) +#include "md.h" +#endif + +#if defined(POLARSSL_MD2_C) +#include "md2.h" +#endif + +#if defined(POLARSSL_MD4_C) +#include "md4.h" +#endif + +#if defined(POLARSSL_MD5_C) +#include "md5.h" +#endif + +#if defined(POLARSSL_NET_C) +#include "net.h" +#endif + +#if defined(POLARSSL_PADLOCK_C) +#include "padlock.h" +#endif + +#if defined(POLARSSL_PBKDF2_C) +#include "pbkdf2.h" +#endif + +#if defined(POLARSSL_PEM_C) +#include "pem.h" +#endif + +#if defined(POLARSSL_PKCS12_C) +#include "pkcs12.h" +#endif + +#if defined(POLARSSL_PKCS5_C) +#include "pkcs5.h" +#endif + +#if defined(POLARSSL_RSA_C) +#include "rsa.h" +#endif + +#if defined(POLARSSL_SHA1_C) +#include "sha1.h" +#endif + +#if defined(POLARSSL_SHA2_C) +#include "sha2.h" +#endif + +#if defined(POLARSSL_SHA4_C) +#include "sha4.h" +#endif + +#if defined(POLARSSL_SSL_TLS_C) +#include "ssl.h" +#endif + +#if defined(POLARSSL_X509_PARSE_C) +#include "x509.h" +#endif + +#if defined(POLARSSL_XTEA_C) +#include "xtea.h" +#endif + + +#include + +#if defined _MSC_VER && !defined snprintf +#define snprintf _snprintf +#endif + +void error_strerror( int ret, char *buf, size_t buflen ) +{ + size_t len; + int use_ret; + + memset( buf, 0x00, buflen ); + + if( ret < 0 ) + ret = -ret; + + if( ret & 0xFF80 ) + { + use_ret = ret & 0xFF80; + + // High level error codes + // +#if defined(POLARSSL_CIPHER_C) + if( use_ret == -(POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE) ) + snprintf( buf, buflen, "CIPHER - The selected feature is not available" ); + if( use_ret == -(POLARSSL_ERR_CIPHER_BAD_INPUT_DATA) ) + snprintf( buf, buflen, "CIPHER - Bad input parameters to function" ); + if( use_ret == -(POLARSSL_ERR_CIPHER_ALLOC_FAILED) ) + snprintf( buf, buflen, "CIPHER - Failed to allocate memory" ); + if( use_ret == -(POLARSSL_ERR_CIPHER_INVALID_PADDING) ) + snprintf( buf, buflen, "CIPHER - Input data contains invalid padding and is rejected" ); + if( use_ret == -(POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED) ) + snprintf( buf, buflen, "CIPHER - Decryption of block requires a full block" ); +#endif /* POLARSSL_CIPHER_C */ + +#if defined(POLARSSL_DHM_C) + if( use_ret == -(POLARSSL_ERR_DHM_BAD_INPUT_DATA) ) + snprintf( buf, buflen, "DHM - Bad input parameters to function" ); + if( use_ret == -(POLARSSL_ERR_DHM_READ_PARAMS_FAILED) ) + snprintf( buf, buflen, "DHM - Reading of the DHM parameters failed" ); + if( use_ret == -(POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED) ) + snprintf( buf, buflen, "DHM - Making of the DHM parameters failed" ); + if( use_ret == -(POLARSSL_ERR_DHM_READ_PUBLIC_FAILED) ) + snprintf( buf, buflen, "DHM - Reading of the public values failed" ); + if( use_ret == -(POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED) ) + snprintf( buf, buflen, "DHM - Making of the public value failed" ); + if( use_ret == -(POLARSSL_ERR_DHM_CALC_SECRET_FAILED) ) + snprintf( buf, buflen, "DHM - Calculation of the DHM secret failed" ); +#endif /* POLARSSL_DHM_C */ + +#if defined(POLARSSL_MD_C) + if( use_ret == -(POLARSSL_ERR_MD_FEATURE_UNAVAILABLE) ) + snprintf( buf, buflen, "MD - The selected feature is not available" ); + if( use_ret == -(POLARSSL_ERR_MD_BAD_INPUT_DATA) ) + snprintf( buf, buflen, "MD - Bad input parameters to function" ); + if( use_ret == -(POLARSSL_ERR_MD_ALLOC_FAILED) ) + snprintf( buf, buflen, "MD - Failed to allocate memory" ); + if( use_ret == -(POLARSSL_ERR_MD_FILE_IO_ERROR) ) + snprintf( buf, buflen, "MD - Opening or reading of file failed" ); +#endif /* POLARSSL_MD_C */ + +#if defined(POLARSSL_PEM_C) + if( use_ret == -(POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT) ) + snprintf( buf, buflen, "PEM - No PEM header or footer found" ); + if( use_ret == -(POLARSSL_ERR_PEM_INVALID_DATA) ) + snprintf( buf, buflen, "PEM - PEM string is not as expected" ); + if( use_ret == -(POLARSSL_ERR_PEM_MALLOC_FAILED) ) + snprintf( buf, buflen, "PEM - Failed to allocate memory" ); + if( use_ret == -(POLARSSL_ERR_PEM_INVALID_ENC_IV) ) + snprintf( buf, buflen, "PEM - RSA IV is not in hex-format" ); + if( use_ret == -(POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG) ) + snprintf( buf, buflen, "PEM - Unsupported key encryption algorithm" ); + if( use_ret == -(POLARSSL_ERR_PEM_PASSWORD_REQUIRED) ) + snprintf( buf, buflen, "PEM - Private key password can't be empty" ); + if( use_ret == -(POLARSSL_ERR_PEM_PASSWORD_MISMATCH) ) + snprintf( buf, buflen, "PEM - Given private key password does not allow for correct decryption" ); + if( use_ret == -(POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE) ) + snprintf( buf, buflen, "PEM - Unavailable feature, e.g. hashing/encryption combination" ); + if( use_ret == -(POLARSSL_ERR_PEM_BAD_INPUT_DATA) ) + snprintf( buf, buflen, "PEM - Bad input parameters to function" ); +#endif /* POLARSSL_PEM_C */ + +#if defined(POLARSSL_PKCS12_C) + if( use_ret == -(POLARSSL_ERR_PKCS12_BAD_INPUT_DATA) ) + snprintf( buf, buflen, "PKCS12 - Bad input parameters to function" ); + if( use_ret == -(POLARSSL_ERR_PKCS12_FEATURE_UNAVAILABLE) ) + snprintf( buf, buflen, "PKCS12 - Feature not available, e.g. unsupported encryption scheme" ); + if( use_ret == -(POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT) ) + snprintf( buf, buflen, "PKCS12 - PBE ASN.1 data not as expected" ); + if( use_ret == -(POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH) ) + snprintf( buf, buflen, "PKCS12 - Given private key password does not allow for correct decryption" ); +#endif /* POLARSSL_PKCS12_C */ + +#if defined(POLARSSL_PKCS5_C) + if( use_ret == -(POLARSSL_ERR_PKCS5_BAD_INPUT_DATA) ) + snprintf( buf, buflen, "PKCS5 - Bad input parameters to function" ); + if( use_ret == -(POLARSSL_ERR_PKCS5_INVALID_FORMAT) ) + snprintf( buf, buflen, "PKCS5 - Unexpected ASN.1 data" ); + if( use_ret == -(POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE) ) + snprintf( buf, buflen, "PKCS5 - Requested encryption or digest alg not available" ); + if( use_ret == -(POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH) ) + snprintf( buf, buflen, "PKCS5 - Given private key password does not allow for correct decryption" ); +#endif /* POLARSSL_PKCS5_C */ + +#if defined(POLARSSL_RSA_C) + if( use_ret == -(POLARSSL_ERR_RSA_BAD_INPUT_DATA) ) + snprintf( buf, buflen, "RSA - Bad input parameters to function" ); + if( use_ret == -(POLARSSL_ERR_RSA_INVALID_PADDING) ) + snprintf( buf, buflen, "RSA - Input data contains invalid padding and is rejected" ); + if( use_ret == -(POLARSSL_ERR_RSA_KEY_GEN_FAILED) ) + snprintf( buf, buflen, "RSA - Something failed during generation of a key" ); + if( use_ret == -(POLARSSL_ERR_RSA_KEY_CHECK_FAILED) ) + snprintf( buf, buflen, "RSA - Key failed to pass the libraries validity check" ); + if( use_ret == -(POLARSSL_ERR_RSA_PUBLIC_FAILED) ) + snprintf( buf, buflen, "RSA - The public key operation failed" ); + if( use_ret == -(POLARSSL_ERR_RSA_PRIVATE_FAILED) ) + snprintf( buf, buflen, "RSA - The private key operation failed" ); + if( use_ret == -(POLARSSL_ERR_RSA_VERIFY_FAILED) ) + snprintf( buf, buflen, "RSA - The PKCS#1 verification failed" ); + if( use_ret == -(POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE) ) + snprintf( buf, buflen, "RSA - The output buffer for decryption is not large enough" ); + if( use_ret == -(POLARSSL_ERR_RSA_RNG_FAILED) ) + snprintf( buf, buflen, "RSA - The random generator failed to generate non-zeros" ); +#endif /* POLARSSL_RSA_C */ + +#if defined(POLARSSL_SSL_TLS_C) + if( use_ret == -(POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE) ) + snprintf( buf, buflen, "SSL - The requested feature is not available" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_INPUT_DATA) ) + snprintf( buf, buflen, "SSL - Bad input parameters to function" ); + if( use_ret == -(POLARSSL_ERR_SSL_INVALID_MAC) ) + snprintf( buf, buflen, "SSL - Verification of the message MAC failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_INVALID_RECORD) ) + snprintf( buf, buflen, "SSL - An invalid SSL record was received" ); + if( use_ret == -(POLARSSL_ERR_SSL_CONN_EOF) ) + snprintf( buf, buflen, "SSL - The connection indicated an EOF" ); + if( use_ret == -(POLARSSL_ERR_SSL_UNKNOWN_CIPHER) ) + snprintf( buf, buflen, "SSL - An unknown cipher was received" ); + if( use_ret == -(POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN) ) + snprintf( buf, buflen, "SSL - The server has no ciphersuites in common with the client" ); + if( use_ret == -(POLARSSL_ERR_SSL_NO_SESSION_FOUND) ) + snprintf( buf, buflen, "SSL - No session to recover was found" ); + if( use_ret == -(POLARSSL_ERR_SSL_NO_CLIENT_CERTIFICATE) ) + snprintf( buf, buflen, "SSL - No client certification received from the client, but required by the authentication mode" ); + if( use_ret == -(POLARSSL_ERR_SSL_CERTIFICATE_TOO_LARGE) ) + snprintf( buf, buflen, "SSL - DESCRIPTION MISSING" ); + if( use_ret == -(POLARSSL_ERR_SSL_CERTIFICATE_REQUIRED) ) + snprintf( buf, buflen, "SSL - The own certificate is not set, but needed by the server" ); + if( use_ret == -(POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED) ) + snprintf( buf, buflen, "SSL - The own private key is not set, but needed" ); + if( use_ret == -(POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED) ) + snprintf( buf, buflen, "SSL - No CA Chain is set, but required to operate" ); + if( use_ret == -(POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE) ) + snprintf( buf, buflen, "SSL - An unexpected message was received from our peer" ); + if( use_ret == -(POLARSSL_ERR_SSL_FATAL_ALERT_MESSAGE) ) + { + snprintf( buf, buflen, "SSL - A fatal alert message was received from our peer" ); + return; + } + if( use_ret == -(POLARSSL_ERR_SSL_PEER_VERIFY_FAILED) ) + snprintf( buf, buflen, "SSL - Verification of our peer failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) ) + snprintf( buf, buflen, "SSL - The peer notified us that the connection is going to be closed" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO) ) + snprintf( buf, buflen, "SSL - Processing of the ClientHello handshake message failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO) ) + snprintf( buf, buflen, "SSL - Processing of the ServerHello handshake message failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE) ) + snprintf( buf, buflen, "SSL - Processing of the Certificate handshake message failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST) ) + snprintf( buf, buflen, "SSL - Processing of the CertificateRequest handshake message failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE) ) + snprintf( buf, buflen, "SSL - Processing of the ServerKeyExchange handshake message failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO_DONE) ) + snprintf( buf, buflen, "SSL - Processing of the ServerHelloDone handshake message failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE) ) + snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_DHM_RP) ) + snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed in DHM Read Public" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_DHM_CS) ) + snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed in DHM Calculate Secret" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY) ) + snprintf( buf, buflen, "SSL - Processing of the CertificateVerify handshake message failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC) ) + snprintf( buf, buflen, "SSL - Processing of the ChangeCipherSpec handshake message failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_FINISHED) ) + snprintf( buf, buflen, "SSL - Processing of the Finished handshake message failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_MALLOC_FAILED) ) + snprintf( buf, buflen, "SSL - Memory allocation failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_HW_ACCEL_FAILED) ) + snprintf( buf, buflen, "SSL - Hardware acceleration function returned with error" ); + if( use_ret == -(POLARSSL_ERR_SSL_HW_ACCEL_FALLTHROUGH) ) + snprintf( buf, buflen, "SSL - Hardware acceleration function skipped / left alone data" ); + if( use_ret == -(POLARSSL_ERR_SSL_COMPRESSION_FAILED) ) + snprintf( buf, buflen, "SSL - Processing of the compression / decompression failed" ); + if( use_ret == -(POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION) ) + snprintf( buf, buflen, "SSL - Handshake protocol not within min/max boundaries" ); +#endif /* POLARSSL_SSL_TLS_C */ + +#if defined(POLARSSL_X509_PARSE_C) + if( use_ret == -(POLARSSL_ERR_X509_FEATURE_UNAVAILABLE) ) + snprintf( buf, buflen, "X509 - Unavailable feature, e.g. RSA hashing/encryption combination" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_INVALID_PEM) ) + snprintf( buf, buflen, "X509 - The PEM-encoded certificate contains invalid elements, e.g. invalid character" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_INVALID_FORMAT) ) + snprintf( buf, buflen, "X509 - The certificate format is invalid, e.g. different type expected" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_INVALID_VERSION) ) + snprintf( buf, buflen, "X509 - The certificate version element is invalid" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_INVALID_SERIAL) ) + snprintf( buf, buflen, "X509 - The serial tag or value is invalid" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_INVALID_ALG) ) + snprintf( buf, buflen, "X509 - The algorithm tag or value is invalid" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_INVALID_NAME) ) + snprintf( buf, buflen, "X509 - The name tag or value is invalid" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_INVALID_DATE) ) + snprintf( buf, buflen, "X509 - The date tag or value is invalid" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_INVALID_PUBKEY) ) + snprintf( buf, buflen, "X509 - The pubkey tag or value is invalid (only RSA is supported)" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE) ) + snprintf( buf, buflen, "X509 - The signature tag or value invalid" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS) ) + snprintf( buf, buflen, "X509 - The extension tag or value is invalid" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION) ) + snprintf( buf, buflen, "X509 - Certificate or CRL has an unsupported version number" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG) ) + snprintf( buf, buflen, "X509 - Signature algorithm (oid) is unsupported" ); + if( use_ret == -(POLARSSL_ERR_X509_UNKNOWN_PK_ALG) ) + snprintf( buf, buflen, "X509 - Key algorithm is unsupported (only RSA is supported)" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_SIG_MISMATCH) ) + snprintf( buf, buflen, "X509 - Certificate signature algorithms do not match. (see \\c ::x509_cert sig_oid)" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_VERIFY_FAILED) ) + snprintf( buf, buflen, "X509 - Certificate verification failed, e.g. CRL, CA or signature check failed" ); + if( use_ret == -(POLARSSL_ERR_X509_KEY_INVALID_VERSION) ) + snprintf( buf, buflen, "X509 - Unsupported RSA key version" ); + if( use_ret == -(POLARSSL_ERR_X509_KEY_INVALID_FORMAT) ) + snprintf( buf, buflen, "X509 - Invalid RSA key tag or value" ); + if( use_ret == -(POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT) ) + snprintf( buf, buflen, "X509 - Format not recognized as DER or PEM" ); + if( use_ret == -(POLARSSL_ERR_X509_INVALID_INPUT) ) + snprintf( buf, buflen, "X509 - Input invalid" ); + if( use_ret == -(POLARSSL_ERR_X509_MALLOC_FAILED) ) + snprintf( buf, buflen, "X509 - Allocation of memory failed" ); + if( use_ret == -(POLARSSL_ERR_X509_FILE_IO_ERROR) ) + snprintf( buf, buflen, "X509 - Read/write of file failed" ); + if( use_ret == -(POLARSSL_ERR_X509_PASSWORD_REQUIRED) ) + snprintf( buf, buflen, "X509 - Private key password can't be empty" ); + if( use_ret == -(POLARSSL_ERR_X509_PASSWORD_MISMATCH) ) + snprintf( buf, buflen, "X509 - Given private key password does not allow for correct decryption" ); +#endif /* POLARSSL_X509_PARSE_C */ + + if( strlen( buf ) == 0 ) + snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret ); + } + + use_ret = ret & ~0xFF80; + + if( use_ret == 0 ) + return; + + // If high level code is present, make a concatenation between both + // error strings. + // + len = strlen( buf ); + + if( len > 0 ) + { + if( buflen - len < 5 ) + return; + + snprintf( buf + len, buflen - len, " : " ); + + buf += len + 3; + buflen -= len + 3; + } + + // Low level error codes + // +#if defined(POLARSSL_AES_C) + if( use_ret == -(POLARSSL_ERR_AES_INVALID_KEY_LENGTH) ) + snprintf( buf, buflen, "AES - Invalid key length" ); + if( use_ret == -(POLARSSL_ERR_AES_INVALID_INPUT_LENGTH) ) + snprintf( buf, buflen, "AES - Invalid data input length" ); +#endif /* POLARSSL_AES_C */ + +#if defined(POLARSSL_ASN1_PARSE_C) + if( use_ret == -(POLARSSL_ERR_ASN1_OUT_OF_DATA) ) + snprintf( buf, buflen, "ASN1 - Out of data when parsing an ASN1 data structure" ); + if( use_ret == -(POLARSSL_ERR_ASN1_UNEXPECTED_TAG) ) + snprintf( buf, buflen, "ASN1 - ASN1 tag was of an unexpected value" ); + if( use_ret == -(POLARSSL_ERR_ASN1_INVALID_LENGTH) ) + snprintf( buf, buflen, "ASN1 - Error when trying to determine the length or invalid length" ); + if( use_ret == -(POLARSSL_ERR_ASN1_LENGTH_MISMATCH) ) + snprintf( buf, buflen, "ASN1 - Actual length differs from expected length" ); + if( use_ret == -(POLARSSL_ERR_ASN1_INVALID_DATA) ) + snprintf( buf, buflen, "ASN1 - Data is invalid. (not used)" ); + if( use_ret == -(POLARSSL_ERR_ASN1_MALLOC_FAILED) ) + snprintf( buf, buflen, "ASN1 - Memory allocation failed" ); + if( use_ret == -(POLARSSL_ERR_ASN1_BUF_TOO_SMALL) ) + snprintf( buf, buflen, "ASN1 - Buffer too small when writing ASN.1 data structure" ); +#endif /* POLARSSL_ASN1_PARSE_C */ + +#if defined(POLARSSL_BASE64_C) + if( use_ret == -(POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL) ) + snprintf( buf, buflen, "BASE64 - Output buffer too small" ); + if( use_ret == -(POLARSSL_ERR_BASE64_INVALID_CHARACTER) ) + snprintf( buf, buflen, "BASE64 - Invalid character in input" ); +#endif /* POLARSSL_BASE64_C */ + +#if defined(POLARSSL_BIGNUM_C) + if( use_ret == -(POLARSSL_ERR_MPI_FILE_IO_ERROR) ) + snprintf( buf, buflen, "BIGNUM - An error occurred while reading from or writing to a file" ); + if( use_ret == -(POLARSSL_ERR_MPI_BAD_INPUT_DATA) ) + snprintf( buf, buflen, "BIGNUM - Bad input parameters to function" ); + if( use_ret == -(POLARSSL_ERR_MPI_INVALID_CHARACTER) ) + snprintf( buf, buflen, "BIGNUM - There is an invalid character in the digit string" ); + if( use_ret == -(POLARSSL_ERR_MPI_BUFFER_TOO_SMALL) ) + snprintf( buf, buflen, "BIGNUM - The buffer is too small to write to" ); + if( use_ret == -(POLARSSL_ERR_MPI_NEGATIVE_VALUE) ) + snprintf( buf, buflen, "BIGNUM - The input arguments are negative or result in illegal output" ); + if( use_ret == -(POLARSSL_ERR_MPI_DIVISION_BY_ZERO) ) + snprintf( buf, buflen, "BIGNUM - The input argument for division is zero, which is not allowed" ); + if( use_ret == -(POLARSSL_ERR_MPI_NOT_ACCEPTABLE) ) + snprintf( buf, buflen, "BIGNUM - The input arguments are not acceptable" ); + if( use_ret == -(POLARSSL_ERR_MPI_MALLOC_FAILED) ) + snprintf( buf, buflen, "BIGNUM - Memory allocation failed" ); +#endif /* POLARSSL_BIGNUM_C */ + +#if defined(POLARSSL_BLOWFISH_C) + if( use_ret == -(POLARSSL_ERR_BLOWFISH_INVALID_KEY_LENGTH) ) + snprintf( buf, buflen, "BLOWFISH - Invalid key length" ); + if( use_ret == -(POLARSSL_ERR_BLOWFISH_INVALID_INPUT_LENGTH) ) + snprintf( buf, buflen, "BLOWFISH - Invalid data input length" ); +#endif /* POLARSSL_BLOWFISH_C */ + +#if defined(POLARSSL_CAMELLIA_C) + if( use_ret == -(POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH) ) + snprintf( buf, buflen, "CAMELLIA - Invalid key length" ); + if( use_ret == -(POLARSSL_ERR_CAMELLIA_INVALID_INPUT_LENGTH) ) + snprintf( buf, buflen, "CAMELLIA - Invalid data input length" ); +#endif /* POLARSSL_CAMELLIA_C */ + +#if defined(POLARSSL_CTR_DRBG_C) + if( use_ret == -(POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED) ) + snprintf( buf, buflen, "CTR_DRBG - The entropy source failed" ); + if( use_ret == -(POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG) ) + snprintf( buf, buflen, "CTR_DRBG - Too many random requested in single call" ); + if( use_ret == -(POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG) ) + snprintf( buf, buflen, "CTR_DRBG - Input too large (Entropy + additional)" ); + if( use_ret == -(POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR) ) + snprintf( buf, buflen, "CTR_DRBG - Read/write error in file" ); +#endif /* POLARSSL_CTR_DRBG_C */ + +#if defined(POLARSSL_DES_C) + if( use_ret == -(POLARSSL_ERR_DES_INVALID_INPUT_LENGTH) ) + snprintf( buf, buflen, "DES - The data input has an invalid length" ); +#endif /* POLARSSL_DES_C */ + +#if defined(POLARSSL_ENTROPY_C) + if( use_ret == -(POLARSSL_ERR_ENTROPY_SOURCE_FAILED) ) + snprintf( buf, buflen, "ENTROPY - Critical entropy source failure" ); + if( use_ret == -(POLARSSL_ERR_ENTROPY_MAX_SOURCES) ) + snprintf( buf, buflen, "ENTROPY - No more sources can be added" ); + if( use_ret == -(POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED) ) + snprintf( buf, buflen, "ENTROPY - No sources have been added to poll" ); +#endif /* POLARSSL_ENTROPY_C */ + +#if defined(POLARSSL_GCM_C) + if( use_ret == -(POLARSSL_ERR_GCM_AUTH_FAILED) ) + snprintf( buf, buflen, "GCM - Authenticated decryption failed" ); + if( use_ret == -(POLARSSL_ERR_GCM_BAD_INPUT) ) + snprintf( buf, buflen, "GCM - Bad input parameters to function" ); +#endif /* POLARSSL_GCM_C */ + +#if defined(POLARSSL_MD2_C) + if( use_ret == -(POLARSSL_ERR_MD2_FILE_IO_ERROR) ) + snprintf( buf, buflen, "MD2 - Read/write error in file" ); +#endif /* POLARSSL_MD2_C */ + +#if defined(POLARSSL_MD4_C) + if( use_ret == -(POLARSSL_ERR_MD4_FILE_IO_ERROR) ) + snprintf( buf, buflen, "MD4 - Read/write error in file" ); +#endif /* POLARSSL_MD4_C */ + +#if defined(POLARSSL_MD5_C) + if( use_ret == -(POLARSSL_ERR_MD5_FILE_IO_ERROR) ) + snprintf( buf, buflen, "MD5 - Read/write error in file" ); +#endif /* POLARSSL_MD5_C */ + +#if defined(POLARSSL_NET_C) + if( use_ret == -(POLARSSL_ERR_NET_UNKNOWN_HOST) ) + snprintf( buf, buflen, "NET - Failed to get an IP address for the given hostname" ); + if( use_ret == -(POLARSSL_ERR_NET_SOCKET_FAILED) ) + snprintf( buf, buflen, "NET - Failed to open a socket" ); + if( use_ret == -(POLARSSL_ERR_NET_CONNECT_FAILED) ) + snprintf( buf, buflen, "NET - The connection to the given server / port failed" ); + if( use_ret == -(POLARSSL_ERR_NET_BIND_FAILED) ) + snprintf( buf, buflen, "NET - Binding of the socket failed" ); + if( use_ret == -(POLARSSL_ERR_NET_LISTEN_FAILED) ) + snprintf( buf, buflen, "NET - Could not listen on the socket" ); + if( use_ret == -(POLARSSL_ERR_NET_ACCEPT_FAILED) ) + snprintf( buf, buflen, "NET - Could not accept the incoming connection" ); + if( use_ret == -(POLARSSL_ERR_NET_RECV_FAILED) ) + snprintf( buf, buflen, "NET - Reading information from the socket failed" ); + if( use_ret == -(POLARSSL_ERR_NET_SEND_FAILED) ) + snprintf( buf, buflen, "NET - Sending information through the socket failed" ); + if( use_ret == -(POLARSSL_ERR_NET_CONN_RESET) ) + snprintf( buf, buflen, "NET - Connection was reset by peer" ); + if( use_ret == -(POLARSSL_ERR_NET_WANT_READ) ) + snprintf( buf, buflen, "NET - Connection requires a read call" ); + if( use_ret == -(POLARSSL_ERR_NET_WANT_WRITE) ) + snprintf( buf, buflen, "NET - Connection requires a write call" ); +#endif /* POLARSSL_NET_C */ + +#if defined(POLARSSL_PADLOCK_C) + if( use_ret == -(POLARSSL_ERR_PADLOCK_DATA_MISALIGNED) ) + snprintf( buf, buflen, "PADLOCK - Input data should be aligned" ); +#endif /* POLARSSL_PADLOCK_C */ + +#if defined(POLARSSL_PBKDF2_C) + if( use_ret == -(POLARSSL_ERR_PBKDF2_BAD_INPUT_DATA) ) + snprintf( buf, buflen, "PBKDF2 - Bad input parameters to function" ); +#endif /* POLARSSL_PBKDF2_C */ + +#if defined(POLARSSL_SHA1_C) + if( use_ret == -(POLARSSL_ERR_SHA1_FILE_IO_ERROR) ) + snprintf( buf, buflen, "SHA1 - Read/write error in file" ); +#endif /* POLARSSL_SHA1_C */ + +#if defined(POLARSSL_SHA2_C) + if( use_ret == -(POLARSSL_ERR_SHA2_FILE_IO_ERROR) ) + snprintf( buf, buflen, "SHA2 - Read/write error in file" ); +#endif /* POLARSSL_SHA2_C */ + +#if defined(POLARSSL_SHA4_C) + if( use_ret == -(POLARSSL_ERR_SHA4_FILE_IO_ERROR) ) + snprintf( buf, buflen, "SHA4 - Read/write error in file" ); +#endif /* POLARSSL_SHA4_C */ + +#if defined(POLARSSL_XTEA_C) + if( use_ret == -(POLARSSL_ERR_XTEA_INVALID_INPUT_LENGTH) ) + snprintf( buf, buflen, "XTEA - The data input has an invalid length" ); +#endif /* POLARSSL_XTEA_C */ + + if( strlen( buf ) != 0 ) + return; + + snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret ); +} + +#else /* POLARSSL_ERROR_C */ + +#if defined(POLARSSL_ERROR_STRERROR_DUMMY) + +#include + +/* + * Provide an non-function in case POLARSSL_ERROR_C is not defined + */ +void error_strerror( int ret, char *buf, size_t buflen ) +{ + ((void) ret); + + if( buflen > 0 ) + buf[0] = '\0'; +} + +#endif /* POLARSSL_ERROR_STRERROR_DUMMY */ +#endif /* POLARSSL_ERROR_C */ diff --git a/src/libpolarssl/error.h b/src/libpolarssl/error.h new file mode 100644 index 0000000..94c73a8 --- /dev/null +++ b/src/libpolarssl/error.h @@ -0,0 +1,108 @@ +/** + * \file error.h + * + * \brief Error to string translation + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_ERROR_H +#define POLARSSL_ERROR_H + +#include + +/** + * Error code layout. + * + * Currently we try to keep all error codes within the negative space of 16 + * bytes signed integers to support all platforms (-0x0000 - -0x8000). In + * addition we'd like to give two layers of information on the error if + * possible. + * + * For that purpose the error codes are segmented in the following manner: + * + * 16 bit error code bit-segmentation + * + * 1 bit - Intentionally not used + * 3 bits - High level module ID + * 5 bits - Module-dependent error code + * 6 bits - Low level module errors + * 1 bit - Intentionally not used + * + * Low-level module errors (0x007E-0x0002) + * + * Module Nr Codes assigned + * MPI 7 0x0002-0x0010 + * GCM 2 0x0012-0x0014 + * BLOWFISH 2 0x0016-0x0018 + * AES 2 0x0020-0x0022 + * CAMELLIA 2 0x0024-0x0026 + * XTEA 1 0x0028-0x0028 + * BASE64 2 0x002A-0x002C + * PADLOCK 1 0x0030-0x0030 + * DES 1 0x0032-0x0032 + * CTR_DBRG 3 0x0034-0x003A + * ENTROPY 3 0x003C-0x0040 + * NET 11 0x0042-0x0056 + * ASN1 7 0x0060-0x006C + * MD2 1 0x0070-0x0070 + * MD4 1 0x0072-0x0072 + * MD5 1 0x0074-0x0074 + * SHA1 1 0x0076-0x0076 + * SHA2 1 0x0078-0x0078 + * SHA4 1 0x007A-0x007A + * + * High-level module nr (3 bits - 0x1...-0x8...) + * Name ID Nr of Errors + * PEM 1 9 + * PKCS#12 1 4 (Started from top) + * X509 2 23 + * DHM 3 6 + * PKCS5 3 4 (Started from top) + * RSA 4 9 + * MD 5 4 + * CIPHER 6 5 + * SSL 6 2 (Started from top) + * SSL 7 31 + * + * Module dependent error code (5 bits 0x.08.-0x.F8.) + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Translate a PolarSSL error code into a string representation, + * Result is truncated if necessary and always includes a terminating + * null byte. + * + * \param errnum error code + * \param buffer buffer to place representation in + * \param buflen length of the buffer + */ +void error_strerror( int errnum, char *buffer, size_t buflen ); + +#ifdef __cplusplus +} +#endif + +#endif /* error.h */ diff --git a/src/libpolarssl/gcm.c b/src/libpolarssl/gcm.c new file mode 100644 index 0000000..4f089da --- /dev/null +++ b/src/libpolarssl/gcm.c @@ -0,0 +1,621 @@ +/* + * NIST SP800-38D compliant GCM implementation + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + */ +#include "config.h" + +#if defined(POLARSSL_GCM_C) + +#include "gcm.h" + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +static void gcm_gen_table( gcm_context *ctx ) +{ + int i, j; + uint64_t hi, lo; + uint64_t vl, vh; + unsigned char h[16]; + + memset( h, 0, 16 ); + aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, h, h ); + + ctx->HH[0] = 0; + ctx->HL[0] = 0; + + GET_UINT32_BE( hi, h, 0 ); + GET_UINT32_BE( lo, h, 4 ); + vh = (uint64_t) hi << 32 | lo; + + GET_UINT32_BE( hi, h, 8 ); + GET_UINT32_BE( lo, h, 12 ); + vl = (uint64_t) hi << 32 | lo; + + ctx->HL[8] = vl; + ctx->HH[8] = vh; + + for( i = 4; i > 0; i >>= 1 ) + { + uint32_t T = ( vl & 1 ) * 0xe1000000U; + vl = ( vh << 63 ) | ( vl >> 1 ); + vh = ( vh >> 1 ) ^ ( (uint64_t) T << 32); + + ctx->HL[i] = vl; + ctx->HH[i] = vh; + } + + for (i = 2; i < 16; i <<= 1 ) + { + uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i; + vh = *HiH; + vl = *HiL; + for( j = 1; j < i; j++ ) + { + HiH[j] = vh ^ ctx->HH[j]; + HiL[j] = vl ^ ctx->HL[j]; + } + } + +} + +int gcm_init( gcm_context *ctx, const unsigned char *key, unsigned int keysize ) +{ + int ret; + + memset( ctx, 0, sizeof(gcm_context) ); + + if( ( ret = aes_setkey_enc( &ctx->aes_ctx, key, keysize ) ) != 0 ) + return( ret ); + + gcm_gen_table( ctx ); + + return( 0 ); +} + +static const uint64_t last4[16] = +{ + 0x0000, 0x1c20, 0x3840, 0x2460, + 0x7080, 0x6ca0, 0x48c0, 0x54e0, + 0xe100, 0xfd20, 0xd940, 0xc560, + 0x9180, 0x8da0, 0xa9c0, 0xb5e0 +}; + +void gcm_mult( gcm_context *ctx, const unsigned char x[16], unsigned char output[16] ) +{ + int i = 0; + unsigned char z[16]; + unsigned char lo, hi, rem; + uint64_t zh, zl; + + memset( z, 0x00, 16 ); + + lo = x[15] & 0xf; + hi = x[15] >> 4; + + zh = ctx->HH[lo]; + zl = ctx->HL[lo]; + + for( i = 15; i >= 0; i-- ) + { + lo = x[i] & 0xf; + hi = x[i] >> 4; + + if( i != 15 ) + { + rem = (unsigned char) zl & 0xf; + zl = ( zh << 60 ) | ( zl >> 4 ); + zh = ( zh >> 4 ); + zh ^= (uint64_t) last4[rem] << 48; + zh ^= ctx->HH[lo]; + zl ^= ctx->HL[lo]; + + } + + rem = (unsigned char) zl & 0xf; + zl = ( zh << 60 ) | ( zl >> 4 ); + zh = ( zh >> 4 ); + zh ^= (uint64_t) last4[rem] << 48; + zh ^= ctx->HH[hi]; + zl ^= ctx->HL[hi]; + } + + PUT_UINT32_BE( zh >> 32, output, 0 ); + PUT_UINT32_BE( zh, output, 4 ); + PUT_UINT32_BE( zl >> 32, output, 8 ); + PUT_UINT32_BE( zl, output, 12 ); +} + +int gcm_crypt_and_tag( gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag ) +{ + unsigned char y[16]; + unsigned char ectr[16]; + unsigned char buf[16]; + unsigned char work_buf[16]; + size_t i; + const unsigned char *p; + unsigned char *out_p = output; + size_t use_len; + uint64_t orig_len = length * 8; + uint64_t orig_add_len = add_len * 8; + + memset( y, 0x00, 16 ); + memset( work_buf, 0x00, 16 ); + memset( tag, 0x00, tag_len ); + memset( buf, 0x00, 16 ); + + if( ( mode == GCM_DECRYPT && output <= input && ( input - output ) < 8 ) || + ( output > input && (size_t) ( output - input ) < length ) ) + { + return( POLARSSL_ERR_GCM_BAD_INPUT ); + } + + if( iv_len == 12 ) + { + memcpy( y, iv, iv_len ); + y[15] = 1; + } + else + { + memset( work_buf, 0x00, 16 ); + PUT_UINT32_BE( iv_len * 8, work_buf, 12 ); + + p = iv; + while( iv_len > 0 ) + { + use_len = ( iv_len < 16 ) ? iv_len : 16; + + for( i = 0; i < use_len; i++ ) + y[i] ^= p[i]; + + gcm_mult( ctx, y, y ); + + iv_len -= use_len; + p += use_len; + } + + for( i = 0; i < 16; i++ ) + y[i] ^= work_buf[i]; + + gcm_mult( ctx, y, y ); + } + + aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, y, ectr ); + memcpy( tag, ectr, tag_len ); + + p = add; + while( add_len > 0 ) + { + use_len = ( add_len < 16 ) ? add_len : 16; + + for( i = 0; i < use_len; i++ ) + buf[i] ^= p[i]; + + gcm_mult( ctx, buf, buf ); + + add_len -= use_len; + p += use_len; + } + + p = input; + while( length > 0 ) + { + use_len = ( length < 16 ) ? length : 16; + + for( i = 16; i > 12; i-- ) + if( ++y[i - 1] != 0 ) + break; + + aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, y, ectr ); + + for( i = 0; i < use_len; i++ ) + { + out_p[i] = ectr[i] ^ p[i]; + if( mode == GCM_ENCRYPT ) + buf[i] ^= out_p[i]; + else + buf[i] ^= p[i]; + } + + gcm_mult( ctx, buf, buf ); + + length -= use_len; + p += use_len; + out_p += use_len; + } + + if( orig_len || orig_add_len ) + { + memset( work_buf, 0x00, 16 ); + + PUT_UINT32_BE( ( orig_add_len >> 32 ), work_buf, 0 ); + PUT_UINT32_BE( ( orig_add_len ), work_buf, 4 ); + PUT_UINT32_BE( ( orig_len >> 32 ), work_buf, 8 ); + PUT_UINT32_BE( ( orig_len ), work_buf, 12 ); + + for( i = 0; i < 16; i++ ) + buf[i] ^= work_buf[i]; + + gcm_mult( ctx, buf, buf ); + + for( i = 0; i < tag_len; i++ ) + tag[i] ^= buf[i]; + } + + return( 0 ); +} + +int gcm_auth_decrypt( gcm_context *ctx, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *tag, + size_t tag_len, + const unsigned char *input, + unsigned char *output ) +{ + unsigned char check_tag[16]; + + gcm_crypt_and_tag( ctx, GCM_DECRYPT, length, iv, iv_len, add, add_len, input, output, tag_len, check_tag ); + + if( memcmp( check_tag, tag, tag_len ) == 0 ) + return( 0 ); + + memset( output, 0, length ); + + return( POLARSSL_ERR_GCM_AUTH_FAILED ); +} + +#if defined(POLARSSL_SELF_TEST) + +#include + +/* + * GCM test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip + */ +#define MAX_TESTS 6 + +int key_index[MAX_TESTS] = + { 0, 0, 1, 1, 1, 1 }; + +unsigned char key[MAX_TESTS][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, +}; + +size_t iv_len[MAX_TESTS] = + { 12, 12, 12, 12, 8, 60 }; + +int iv_index[MAX_TESTS] = + { 0, 0, 1, 1, 1, 2 }; + +unsigned char iv[MAX_TESTS][64] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + { 0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, + 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa, + 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, + 0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28, + 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, + 0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, + 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57, + 0xa6, 0x37, 0xb3, 0x9b }, +}; + +size_t add_len[MAX_TESTS] = + { 0, 0, 0, 20, 20, 20 }; + +int add_index[MAX_TESTS] = + { 0, 0, 0, 1, 1, 1 }; + +unsigned char additional[MAX_TESTS][64] = +{ + { 0x00 }, + { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 }, +}; + +size_t pt_len[MAX_TESTS] = + { 0, 16, 64, 60, 60, 60 }; + +int pt_index[MAX_TESTS] = + { 0, 0, 1, 1, 1, 1 }; + +unsigned char pt[MAX_TESTS][64] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, +}; + +unsigned char ct[MAX_TESTS * 3][64] = +{ + { 0x00 }, + { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, + 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78 }, + { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 }, + { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91 }, + { 0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a, + 0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a, 0x47, 0x55, + 0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8, + 0x37, 0x66, 0xe5, 0xf9, 0x7b, 0x6c, 0x74, 0x23, + 0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2, + 0x2b, 0x09, 0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42, + 0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07, + 0xc2, 0x3f, 0x45, 0x98 }, + { 0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6, + 0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f, 0xb8, 0x94, + 0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8, + 0xba, 0x26, 0x2a, 0x3c, 0xca, 0x7e, 0x2c, 0xa7, + 0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90, + 0xcc, 0xdc, 0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f, + 0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03, + 0x4c, 0x34, 0xae, 0xe5 }, + { 0x00 }, + { 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41, + 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00 }, + { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56 }, + { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10 }, + { 0x0f, 0x10, 0xf5, 0x99, 0xae, 0x14, 0xa1, 0x54, + 0xed, 0x24, 0xb3, 0x6e, 0x25, 0x32, 0x4d, 0xb8, + 0xc5, 0x66, 0x63, 0x2e, 0xf2, 0xbb, 0xb3, 0x4f, + 0x83, 0x47, 0x28, 0x0f, 0xc4, 0x50, 0x70, 0x57, + 0xfd, 0xdc, 0x29, 0xdf, 0x9a, 0x47, 0x1f, 0x75, + 0xc6, 0x65, 0x41, 0xd4, 0xd4, 0xda, 0xd1, 0xc9, + 0xe9, 0x3a, 0x19, 0xa5, 0x8e, 0x8b, 0x47, 0x3f, + 0xa0, 0xf0, 0x62, 0xf7 }, + { 0xd2, 0x7e, 0x88, 0x68, 0x1c, 0xe3, 0x24, 0x3c, + 0x48, 0x30, 0x16, 0x5a, 0x8f, 0xdc, 0xf9, 0xff, + 0x1d, 0xe9, 0xa1, 0xd8, 0xe6, 0xb4, 0x47, 0xef, + 0x6e, 0xf7, 0xb7, 0x98, 0x28, 0x66, 0x6e, 0x45, + 0x81, 0xe7, 0x90, 0x12, 0xaf, 0x34, 0xdd, 0xd9, + 0xe2, 0xf0, 0x37, 0x58, 0x9b, 0x29, 0x2d, 0xb3, + 0xe6, 0x7c, 0x03, 0x67, 0x45, 0xfa, 0x22, 0xe7, + 0xe9, 0xb7, 0x37, 0x3b }, + { 0x00 }, + { 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, + 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18 }, + { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad }, + { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62 }, + { 0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32, + 0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98, 0x44, 0xcb, + 0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa, + 0xc5, 0x2f, 0xf7, 0xd7, 0x9b, 0xba, 0x9d, 0xe0, + 0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0, + 0x95, 0x4c, 0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78, + 0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99, + 0xf4, 0x7c, 0x9b, 0x1f }, + { 0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1, + 0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e, 0x2a, 0x20, + 0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19, + 0xa0, 0x58, 0xab, 0x4f, 0x6f, 0x74, 0x6b, 0xf4, + 0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45, + 0x2d, 0xa3, 0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde, + 0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e, + 0x44, 0xae, 0x7e, 0x3f }, +}; + +unsigned char tag[MAX_TESTS * 3][16] = +{ + { 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61, + 0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a }, + { 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd, + 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf }, + { 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 }, + { 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, + 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47 }, + { 0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85, + 0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2, 0xfc, 0xcb }, + { 0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa, + 0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50 }, + { 0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b, + 0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35 }, + { 0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, + 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb }, + { 0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf, + 0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14 }, + { 0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f, + 0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c }, + { 0x65, 0xdc, 0xc5, 0x7f, 0xcf, 0x62, 0x3a, 0x24, + 0x09, 0x4f, 0xcc, 0xa4, 0x0d, 0x35, 0x33, 0xf8 }, + { 0xdc, 0xf5, 0x66, 0xff, 0x29, 0x1c, 0x25, 0xbb, + 0xb8, 0x56, 0x8f, 0xc3, 0xd3, 0x76, 0xa6, 0xd9 }, + { 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, + 0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b }, + { 0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0, + 0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19 }, + { 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd, + 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c }, + { 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, + 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b }, + { 0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4, + 0x5e, 0x45, 0x49, 0x13, 0xfe, 0x2e, 0xa8, 0xf2 }, + { 0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0, + 0xc8, 0xb5, 0xd4, 0xcf, 0x5a, 0xe9, 0xf1, 0x9a }, +}; + +int gcm_self_test( int verbose ) +{ + gcm_context ctx; + unsigned char buf[64]; + unsigned char tag_buf[16]; + int i, j, ret; + + for( j = 0; j < 3; j++ ) + { + int key_len = 128 + 64 * j; + + for( i = 0; i < MAX_TESTS; i++ ) + { + printf( " AES-GCM-%3d #%d (%s): ", key_len, i, "enc" ); + gcm_init( &ctx, key[key_index[i]], key_len ); + + ret = gcm_crypt_and_tag( &ctx, GCM_ENCRYPT, + pt_len[i], + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i], + pt[pt_index[i]], buf, 16, tag_buf ); + + if( ret != 0 || + memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + + printf( " AES-GCM-%3d #%d (%s): ", key_len, i, "dec" ); + gcm_init( &ctx, key[key_index[i]], key_len ); + + ret = gcm_crypt_and_tag( &ctx, GCM_DECRYPT, + pt_len[i], + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i], + ct[j * 6 + i], buf, 16, tag_buf ); + + if( ret != 0 || + memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + } + + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/gcm.h b/src/libpolarssl/gcm.h new file mode 100644 index 0000000..77baa17 --- /dev/null +++ b/src/libpolarssl/gcm.h @@ -0,0 +1,147 @@ +/** + * \file gcm.h + * + * \brief Galois/Counter mode for AES + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_GCM_H +#define POLARSSL_GCM_H + +#include "aes.h" + +#ifdef _MSC_VER +#include +typedef UINT64 uint64_t; +#else +#include +#endif + +#define GCM_ENCRYPT 1 +#define GCM_DECRYPT 0 + +#define POLARSSL_ERR_GCM_AUTH_FAILED -0x0012 /**< Authenticated decryption failed. */ +#define POLARSSL_ERR_GCM_BAD_INPUT -0x0014 /**< Bad input parameters to function. */ + +/** + * \brief GCM context structure + */ +typedef struct { + aes_context aes_ctx; /*!< AES context used */ + uint64_t HL[16]; /*!< Precalculated HTable */ + uint64_t HH[16]; /*!< Precalculated HTable */ +} +gcm_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief GCM initialization (encryption) + * + * \param ctx GCM context to be initialized + * \param key encryption key + * \param keysize must be 128, 192 or 256 + * + * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH + */ +int gcm_init( gcm_context *ctx, const unsigned char *key, unsigned int keysize ); + +/** + * \brief GCM buffer encryption/decryption using AES + * + * \note On encryption, the output buffer can be the same as the input buffer. + * On decryption, the output buffer cannot be the same as input buffer. + * If buffers overlap, the output buffer must trail at least 8 bytes + * behind the input buffer. + * + * \param ctx GCM context + * \param mode GCM_ENCRYPT or GCM_DECRYPT + * \param length length of the input data + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * \param input buffer holding the input data + * \param output buffer for holding the output data + * \param tag_len length of the tag to generate + * \param tag buffer for holding the tag + * + * \return 0 if successful + */ +int gcm_crypt_and_tag( gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag ); + +/** + * \brief GCM buffer authenticated decryption using AES + * + * \note On decryption, the output buffer cannot be the same as input buffer. + * If buffers overlap, the output buffer must trail at least 8 bytes + * behind the input buffer. + * + * \param ctx GCM context + * \param length length of the input data + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * \param tag buffer holding the tag + * \param tag_len length of the tag + * \param input buffer holding the input data + * \param output buffer for holding the output data + * + * \return 0 if successful and authenticated, + * POLARSSL_ERR_GCM_AUTH_FAILED if tag does not match + */ +int gcm_auth_decrypt( gcm_context *ctx, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *tag, + size_t tag_len, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int gcm_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* gcm.h */ diff --git a/src/libpolarssl/havege.c b/src/libpolarssl/havege.c new file mode 100644 index 0000000..ae48829 --- /dev/null +++ b/src/libpolarssl/havege.c @@ -0,0 +1,231 @@ +/** + * \brief HAVEGE: HArdware Volatile Entropy Gathering and Expansion + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The HAVEGE RNG was designed by Andre Seznec in 2002. + * + * http://www.irisa.fr/caps/projects/hipsor/publi.php + * + * Contact: seznec(at)irisa_dot_fr - orocheco(at)irisa_dot_fr + */ + +#include "config.h" + +#if defined(POLARSSL_HAVEGE_C) + +#include "havege.h" +#include "timing.h" + +#include +#include + +/* ------------------------------------------------------------------------ + * On average, one iteration accesses two 8-word blocks in the havege WALK + * table, and generates 16 words in the RES array. + * + * The data read in the WALK table is updated and permuted after each use. + * The result of the hardware clock counter read is used for this update. + * + * 25 conditional tests are present. The conditional tests are grouped in + * two nested groups of 12 conditional tests and 1 test that controls the + * permutation; on average, there should be 6 tests executed and 3 of them + * should be mispredicted. + * ------------------------------------------------------------------------ + */ + +#define SWAP(X,Y) { int *T = X; X = Y; Y = T; } + +#define TST1_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; +#define TST2_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; + +#define TST1_LEAVE U1++; } +#define TST2_LEAVE U2++; } + +#define ONE_ITERATION \ + \ + PTEST = PT1 >> 20; \ + \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + \ + PTX = (PT1 >> 18) & 7; \ + PT1 &= 0x1FFF; \ + PT2 &= 0x1FFF; \ + CLK = (int) hardclock(); \ + \ + i = 0; \ + A = &WALK[PT1 ]; RES[i++] ^= *A; \ + B = &WALK[PT2 ]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 1]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 4]; RES[i++] ^= *D; \ + \ + IN = (*A >> (1)) ^ (*A << (31)) ^ CLK; \ + *A = (*B >> (2)) ^ (*B << (30)) ^ CLK; \ + *B = IN ^ U1; \ + *C = (*C >> (3)) ^ (*C << (29)) ^ CLK; \ + *D = (*D >> (4)) ^ (*D << (28)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 2]; RES[i++] ^= *A; \ + B = &WALK[PT2 ^ 2]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 3]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 6]; RES[i++] ^= *D; \ + \ + if( PTEST & 1 ) SWAP( A, C ); \ + \ + IN = (*A >> (5)) ^ (*A << (27)) ^ CLK; \ + *A = (*B >> (6)) ^ (*B << (26)) ^ CLK; \ + *B = IN; CLK = (int) hardclock(); \ + *C = (*C >> (7)) ^ (*C << (25)) ^ CLK; \ + *D = (*D >> (8)) ^ (*D << (24)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 4]; \ + B = &WALK[PT2 ^ 1]; \ + \ + PTEST = PT2 >> 1; \ + \ + PT2 = (RES[(i - 8) ^ PTY] ^ WALK[PT2 ^ PTY ^ 7]); \ + PT2 = ((PT2 & 0x1FFF) & (~8)) ^ ((PT1 ^ 8) & 0x8); \ + PTY = (PT2 >> 10) & 7; \ + \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + \ + C = &WALK[PT1 ^ 5]; \ + D = &WALK[PT2 ^ 5]; \ + \ + RES[i++] ^= *A; \ + RES[i++] ^= *B; \ + RES[i++] ^= *C; \ + RES[i++] ^= *D; \ + \ + IN = (*A >> ( 9)) ^ (*A << (23)) ^ CLK; \ + *A = (*B >> (10)) ^ (*B << (22)) ^ CLK; \ + *B = IN ^ U2; \ + *C = (*C >> (11)) ^ (*C << (21)) ^ CLK; \ + *D = (*D >> (12)) ^ (*D << (20)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 6]; RES[i++] ^= *A; \ + B = &WALK[PT2 ^ 3]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 7]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 7]; RES[i++] ^= *D; \ + \ + IN = (*A >> (13)) ^ (*A << (19)) ^ CLK; \ + *A = (*B >> (14)) ^ (*B << (18)) ^ CLK; \ + *B = IN; \ + *C = (*C >> (15)) ^ (*C << (17)) ^ CLK; \ + *D = (*D >> (16)) ^ (*D << (16)) ^ CLK; \ + \ + PT1 = ( RES[(i - 8) ^ PTX] ^ \ + WALK[PT1 ^ PTX ^ 7] ) & (~1); \ + PT1 ^= (PT2 ^ 0x10) & 0x10; \ + \ + for( n++, i = 0; i < 16; i++ ) \ + hs->pool[n % COLLECT_SIZE] ^= RES[i]; + +/* + * Entropy gathering function + */ +static void havege_fill( havege_state *hs ) +{ + int i, n = 0; + int U1, U2, *A, *B, *C, *D; + int PT1, PT2, *WALK, RES[16]; + int PTX, PTY, CLK, PTEST, IN; + + WALK = hs->WALK; + PT1 = hs->PT1; + PT2 = hs->PT2; + + PTX = U1 = 0; + PTY = U2 = 0; + + memset( RES, 0, sizeof( RES ) ); + + while( n < COLLECT_SIZE * 4 ) + { + ONE_ITERATION + ONE_ITERATION + ONE_ITERATION + ONE_ITERATION + } + + hs->PT1 = PT1; + hs->PT2 = PT2; + + hs->offset[0] = 0; + hs->offset[1] = COLLECT_SIZE / 2; +} + +/* + * HAVEGE initialization + */ +void havege_init( havege_state *hs ) +{ + memset( hs, 0, sizeof( havege_state ) ); + + havege_fill( hs ); +} + +/* + * HAVEGE rand function + */ +int havege_random( void *p_rng, unsigned char *buf, size_t len ) +{ + int val; + size_t use_len; + havege_state *hs = (havege_state *) p_rng; + unsigned char *p = buf; + + while( len > 0 ) + { + use_len = len; + if( use_len > sizeof(int) ) + use_len = sizeof(int); + + if( hs->offset[1] >= COLLECT_SIZE ) + havege_fill( hs ); + + val = hs->pool[hs->offset[0]++]; + val ^= hs->pool[hs->offset[1]++]; + + memcpy( p, &val, use_len ); + + len -= use_len; + p += use_len; + } + + return( 0 ); +} + +#endif diff --git a/src/libpolarssl/havege.h b/src/libpolarssl/havege.h new file mode 100644 index 0000000..53c4f38 --- /dev/null +++ b/src/libpolarssl/havege.h @@ -0,0 +1,71 @@ +/** + * \file havege.h + * + * \brief HAVEGE: HArdware Volatile Entropy Gathering and Expansion + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_HAVEGE_H +#define POLARSSL_HAVEGE_H + +#include + +#define COLLECT_SIZE 1024 + +/** + * \brief HAVEGE state structure + */ +typedef struct +{ + int PT1, PT2, offset[2]; + int pool[COLLECT_SIZE]; + int WALK[8192]; +} +havege_state; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief HAVEGE initialization + * + * \param hs HAVEGE state to be initialized + */ +void havege_init( havege_state *hs ); + +/** + * \brief HAVEGE rand function + * + * \param p_rng A HAVEGE state + * \param output Buffer to fill + * \param len Length of buffer + * + * \return 0 + */ +int havege_random( void *p_rng, unsigned char *output, size_t len ); + +#ifdef __cplusplus +} +#endif + +#endif /* havege.h */ diff --git a/src/libpolarssl/md.c b/src/libpolarssl/md.c new file mode 100644 index 0000000..f3d1980 --- /dev/null +++ b/src/libpolarssl/md.c @@ -0,0 +1,297 @@ +/** + * \file md.c + * + * \brief Generic message digest wrapper for PolarSSL + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_MD_C) + +#include "md.h" +#include "md_wrap.h" + +#include + +#if defined _MSC_VER && !defined strcasecmp +#define strcasecmp _stricmp +#endif + +static const int supported_digests[] = { + +#if defined(POLARSSL_MD2_C) + POLARSSL_MD_MD2, +#endif + +#if defined(POLARSSL_MD4_C) + POLARSSL_MD_MD4, +#endif + +#if defined(POLARSSL_MD5_C) + POLARSSL_MD_MD5, +#endif + +#if defined(POLARSSL_SHA1_C) + POLARSSL_MD_SHA1, +#endif + +#if defined(POLARSSL_SHA2_C) + POLARSSL_MD_SHA224, + POLARSSL_MD_SHA256, +#endif + +#if defined(POLARSSL_SHA4_C) + POLARSSL_MD_SHA384, + POLARSSL_MD_SHA512, +#endif + + 0 +}; + +const int *md_list( void ) +{ + return supported_digests; +} + +const md_info_t *md_info_from_string( const char *md_name ) +{ + if( NULL == md_name ) + return NULL; + + /* Get the appropriate digest information */ +#if defined(POLARSSL_MD2_C) + if( !strcasecmp( "MD2", md_name ) ) + return md_info_from_type( POLARSSL_MD_MD2 ); +#endif +#if defined(POLARSSL_MD4_C) + if( !strcasecmp( "MD4", md_name ) ) + return md_info_from_type( POLARSSL_MD_MD4 ); +#endif +#if defined(POLARSSL_MD5_C) + if( !strcasecmp( "MD5", md_name ) ) + return md_info_from_type( POLARSSL_MD_MD5 ); +#endif +#if defined(POLARSSL_SHA1_C) + if( !strcasecmp( "SHA1", md_name ) || !strcasecmp( "SHA", md_name ) ) + return md_info_from_type( POLARSSL_MD_SHA1 ); +#endif +#if defined(POLARSSL_SHA2_C) + if( !strcasecmp( "SHA224", md_name ) ) + return md_info_from_type( POLARSSL_MD_SHA224 ); + if( !strcasecmp( "SHA256", md_name ) ) + return md_info_from_type( POLARSSL_MD_SHA256 ); +#endif +#if defined(POLARSSL_SHA4_C) + if( !strcasecmp( "SHA384", md_name ) ) + return md_info_from_type( POLARSSL_MD_SHA384 ); + if( !strcasecmp( "SHA512", md_name ) ) + return md_info_from_type( POLARSSL_MD_SHA512 ); +#endif + return NULL; +} + +const md_info_t *md_info_from_type( md_type_t md_type ) +{ + switch( md_type ) + { +#if defined(POLARSSL_MD2_C) + case POLARSSL_MD_MD2: + return &md2_info; +#endif +#if defined(POLARSSL_MD4_C) + case POLARSSL_MD_MD4: + return &md4_info; +#endif +#if defined(POLARSSL_MD5_C) + case POLARSSL_MD_MD5: + return &md5_info; +#endif +#if defined(POLARSSL_SHA1_C) + case POLARSSL_MD_SHA1: + return &sha1_info; +#endif +#if defined(POLARSSL_SHA2_C) + case POLARSSL_MD_SHA224: + return &sha224_info; + case POLARSSL_MD_SHA256: + return &sha256_info; +#endif +#if defined(POLARSSL_SHA4_C) + case POLARSSL_MD_SHA384: + return &sha384_info; + case POLARSSL_MD_SHA512: + return &sha512_info; +#endif + default: + return NULL; + } +} + +int md_init_ctx( md_context_t *ctx, const md_info_t *md_info ) +{ + if( md_info == NULL || ctx == NULL ) + return POLARSSL_ERR_MD_BAD_INPUT_DATA; + + memset( ctx, 0, sizeof( md_context_t ) ); + + if( ( ctx->md_ctx = md_info->ctx_alloc_func() ) == NULL ) + return POLARSSL_ERR_MD_ALLOC_FAILED; + + ctx->md_info = md_info; + + md_info->starts_func( ctx->md_ctx ); + + return 0; +} + +int md_free_ctx( md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return POLARSSL_ERR_MD_BAD_INPUT_DATA; + + ctx->md_info->ctx_free_func( ctx->md_ctx ); + ctx->md_ctx = NULL; + + return 0; +} + +int md_starts( md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return POLARSSL_ERR_MD_BAD_INPUT_DATA; + + ctx->md_info->starts_func( ctx->md_ctx ); + + return 0; +} + +int md_update( md_context_t *ctx, const unsigned char *input, size_t ilen ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return POLARSSL_ERR_MD_BAD_INPUT_DATA; + + ctx->md_info->update_func( ctx->md_ctx, input, ilen ); + + return 0; +} + +int md_finish( md_context_t *ctx, unsigned char *output ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return POLARSSL_ERR_MD_BAD_INPUT_DATA; + + ctx->md_info->finish_func( ctx->md_ctx, output ); + + return 0; +} + +int md( const md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + if ( md_info == NULL ) + return POLARSSL_ERR_MD_BAD_INPUT_DATA; + + md_info->digest_func( input, ilen, output ); + + return 0; +} + +int md_file( const md_info_t *md_info, const char *path, unsigned char *output ) +{ +#if defined(POLARSSL_FS_IO) + int ret; +#endif + + if( md_info == NULL ) + return POLARSSL_ERR_MD_BAD_INPUT_DATA; + +#if defined(POLARSSL_FS_IO) + ret = md_info->file_func( path, output ); + if( ret != 0 ) + return( POLARSSL_ERR_MD_FILE_IO_ERROR + ret ); + + return( ret ); +#else + ((void) path); + ((void) output); + + return POLARSSL_ERR_MD_FEATURE_UNAVAILABLE; +#endif +} + +int md_hmac_starts( md_context_t *ctx, const unsigned char *key, size_t keylen ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return POLARSSL_ERR_MD_BAD_INPUT_DATA; + + ctx->md_info->hmac_starts_func( ctx->md_ctx, key, keylen); + + return 0; +} + +int md_hmac_update( md_context_t *ctx, const unsigned char *input, size_t ilen ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return POLARSSL_ERR_MD_BAD_INPUT_DATA; + + ctx->md_info->hmac_update_func( ctx->md_ctx, input, ilen ); + + return 0; +} + +int md_hmac_finish( md_context_t *ctx, unsigned char *output) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return POLARSSL_ERR_MD_BAD_INPUT_DATA; + + ctx->md_info->hmac_finish_func( ctx->md_ctx, output); + + return 0; +} + +int md_hmac_reset( md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return POLARSSL_ERR_MD_BAD_INPUT_DATA; + + ctx->md_info->hmac_reset_func( ctx->md_ctx); + + return 0; +} + +int md_hmac( const md_info_t *md_info, const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + if( md_info == NULL ) + return POLARSSL_ERR_MD_BAD_INPUT_DATA; + + md_info->hmac_func( key, keylen, input, ilen, output ); + + return 0; +} + +#endif diff --git a/src/libpolarssl/md.h b/src/libpolarssl/md.h new file mode 100644 index 0000000..6a1bdd4 --- /dev/null +++ b/src/libpolarssl/md.h @@ -0,0 +1,363 @@ +/** + * \file md.h + * + * \brief Generic message digest wrapper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_MD_H +#define POLARSSL_MD_H + +#include + +#if defined(_MSC_VER) && !defined(inline) +#define inline _inline +#else +#if defined(__ARMCC_VERSION) && !defined(inline) +#define inline __inline +#endif /* __ARMCC_VERSION */ +#endif /*_MSC_VER */ + +#define POLARSSL_ERR_MD_FEATURE_UNAVAILABLE -0x5080 /**< The selected feature is not available. */ +#define POLARSSL_ERR_MD_BAD_INPUT_DATA -0x5100 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_MD_ALLOC_FAILED -0x5180 /**< Failed to allocate memory. */ +#define POLARSSL_ERR_MD_FILE_IO_ERROR -0x5200 /**< Opening or reading of file failed. */ + +typedef enum { + POLARSSL_MD_NONE=0, + POLARSSL_MD_MD2, + POLARSSL_MD_MD4, + POLARSSL_MD_MD5, + POLARSSL_MD_SHA1, + POLARSSL_MD_SHA224, + POLARSSL_MD_SHA256, + POLARSSL_MD_SHA384, + POLARSSL_MD_SHA512, +} md_type_t; + +#define POLARSSL_MD_MAX_SIZE 64 /* longest known is SHA512 */ + +/** + * Message digest information. Allows message digest functions to be called + * in a generic way. + */ +typedef struct { + /** Digest identifier */ + md_type_t type; + + /** Name of the message digest */ + const char * name; + + /** Output length of the digest function */ + int size; + + /** Digest initialisation function */ + void (*starts_func)( void *ctx ); + + /** Digest update function */ + void (*update_func)( void *ctx, const unsigned char *input, size_t ilen ); + + /** Digest finalisation function */ + void (*finish_func)( void *ctx, unsigned char *output ); + + /** Generic digest function */ + void (*digest_func)( const unsigned char *input, size_t ilen, + unsigned char *output ); + + /** Generic file digest function */ + int (*file_func)( const char *path, unsigned char *output ); + + /** HMAC Initialisation function */ + void (*hmac_starts_func)( void *ctx, const unsigned char *key, size_t keylen ); + + /** HMAC update function */ + void (*hmac_update_func)( void *ctx, const unsigned char *input, size_t ilen ); + + /** HMAC finalisation function */ + void (*hmac_finish_func)( void *ctx, unsigned char *output); + + /** HMAC context reset function */ + void (*hmac_reset_func)( void *ctx ); + + /** Generic HMAC function */ + void (*hmac_func)( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + +} md_info_t; + +/** + * Generic message digest context. + */ +typedef struct { + /** Information about the associated message digest */ + const md_info_t *md_info; + + /** Digest-specific context */ + void *md_ctx; +} md_context_t; + +#define MD_CONTEXT_T_INIT { \ + NULL, /* md_info */ \ + NULL, /* md_ctx */ \ +} + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Returns the list of digests supported by the generic digest module. + * + * \return a statically allocated array of digests, the last entry + * is 0. + */ +const int *md_list( void ); + +/** + * \brief Returns the message digest information associated with the + * given digest name. + * + * \param md_name Name of the digest to search for. + * + * \return The message digest information associated with md_name or + * NULL if not found. + */ +const md_info_t *md_info_from_string( const char *md_name ); + +/** + * \brief Returns the message digest information associated with the + * given digest type. + * + * \param md_type type of digest to search for. + * + * \return The message digest information associated with md_type or + * NULL if not found. + */ +const md_info_t *md_info_from_type( md_type_t md_type ); + +/** + * \brief Initialises and fills the message digest context structure with + * the appropriate values. + * + * \param ctx context to initialise. May not be NULL. The + * digest-specific context (ctx->md_ctx) must be NULL. It will + * be allocated, and must be freed using md_free_ctx() later. + * \param md_info message digest to use. + * + * \returns \c 0 on success, \c POLARSSL_ERR_MD_BAD_INPUT_DATA on + * parameter failure, \c POLARSSL_ERR_MD_ALLOC_FAILED if + * allocation of the digest-specific context failed. + */ +int md_init_ctx( md_context_t *ctx, const md_info_t *md_info ); + +/** + * \brief Free the message-specific context of ctx. Freeing ctx itself + * remains the responsibility of the caller. + * + * \param ctx Free the message-specific context + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_free_ctx( md_context_t *ctx ); + +/** + * \brief Returns the size of the message digest output. + * + * \param md_info message digest info + * + * \return size of the message digest output. + */ +static inline unsigned char md_get_size( const md_info_t *md_info ) +{ + if( md_info == NULL ) + return( 0 ); + + return md_info->size; +} + +/** + * \brief Returns the type of the message digest output. + * + * \param md_info message digest info + * + * \return type of the message digest output. + */ +static inline md_type_t md_get_type( const md_info_t *md_info ) +{ + if( md_info == NULL ) + return( POLARSSL_MD_NONE ); + + return md_info->type; +} + +/** + * \brief Returns the name of the message digest output. + * + * \param md_info message digest info + * + * \return name of the message digest output. + */ +static inline const char *md_get_name( const md_info_t *md_info ) +{ + if( md_info == NULL ) + return( NULL ); + + return md_info->name; +} + +/** + * \brief Set-up the given context for a new message digest + * + * \param ctx generic message digest context. + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_starts( md_context_t *ctx ); + +/** + * \brief Generic message digest process buffer + * + * \param ctx Generic message digest context + * \param input buffer holding the datal + * \param ilen length of the input data + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_update( md_context_t *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief Generic message digest final digest + * + * \param ctx Generic message digest context + * \param output Generic message digest checksum result + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_finish( md_context_t *ctx, unsigned char *output ); + +/** + * \brief Output = message_digest( input buffer ) + * + * \param md_info message digest info + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic message digest checksum result + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md( const md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ); + +/** + * \brief Output = message_digest( file contents ) + * + * \param md_info message digest info + * \param path input file name + * \param output generic message digest checksum result + * + * \return 0 if successful, POLARSSL_ERR_MD_FILE_OPEN_FAILED if fopen + * failed, POLARSSL_ERR_MD_FILE_READ_FAILED if fread failed, + * POLARSSL_ERR_MD_BAD_INPUT_DATA if md_info was NULL. + */ +int md_file( const md_info_t *md_info, const char *path, unsigned char *output ); + +/** + * \brief Generic HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_hmac_starts( md_context_t *ctx, const unsigned char *key, size_t keylen ); + +/** + * \brief Generic HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_hmac_update( md_context_t *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief Generic HMAC final digest + * + * \param ctx HMAC context + * \param output Generic HMAC checksum result + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_hmac_finish( md_context_t *ctx, unsigned char *output); + +/** + * \brief Generic HMAC context reset + * + * \param ctx HMAC context to be reset + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_hmac_reset( md_context_t *ctx ); + +/** + * \brief Output = Generic_HMAC( hmac key, input buffer ) + * + * \param md_info message digest info + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic HMAC-result + * + * \returns 0 on success, POLARSSL_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int md_hmac( const md_info_t *md_info, const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#endif /* POLARSSL_MD_H */ diff --git a/src/libpolarssl/md2.c b/src/libpolarssl/md2.c new file mode 100644 index 0000000..fe815e7 --- /dev/null +++ b/src/libpolarssl/md2.c @@ -0,0 +1,368 @@ +/* + * RFC 1115/1319 compliant MD2 implementation + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The MD2 algorithm was designed by Ron Rivest in 1989. + * + * http://www.ietf.org/rfc/rfc1115.txt + * http://www.ietf.org/rfc/rfc1319.txt + */ + +#include "config.h" + +#if defined(POLARSSL_MD2_C) + +#include "md2.h" + +#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST) +#include +#endif + +#if !defined(POLARSSL_MD2_ALT) + +static const unsigned char PI_SUBST[256] = +{ + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, + 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3, + 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, + 0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, + 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E, + 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, + 0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, + 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, + 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, + 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3, + 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, + 0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, + 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D, + 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, + 0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, + 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, + 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, + 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E, + 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, + 0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, + 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88, + 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, + 0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, + 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, + 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14 +}; + +/* + * MD2 context setup + */ +void md2_starts( md2_context *ctx ) +{ + memset( ctx->cksum, 0, 16 ); + memset( ctx->state, 0, 46 ); + memset( ctx->buffer, 0, 16 ); + ctx->left = 0; +} + +static void md2_process( md2_context *ctx ) +{ + int i, j; + unsigned char t = 0; + + for( i = 0; i < 16; i++ ) + { + ctx->state[i + 16] = ctx->buffer[i]; + ctx->state[i + 32] = + (unsigned char)( ctx->buffer[i] ^ ctx->state[i]); + } + + for( i = 0; i < 18; i++ ) + { + for( j = 0; j < 48; j++ ) + { + ctx->state[j] = (unsigned char) + ( ctx->state[j] ^ PI_SUBST[t] ); + t = ctx->state[j]; + } + + t = (unsigned char)( t + i ); + } + + t = ctx->cksum[15]; + + for( i = 0; i < 16; i++ ) + { + ctx->cksum[i] = (unsigned char) + ( ctx->cksum[i] ^ PI_SUBST[ctx->buffer[i] ^ t] ); + t = ctx->cksum[i]; + } +} + +/* + * MD2 process buffer + */ +void md2_update( md2_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + + while( ilen > 0 ) + { + if( ctx->left + ilen > 16 ) + fill = 16 - ctx->left; + else + fill = ilen; + + memcpy( ctx->buffer + ctx->left, input, fill ); + + ctx->left += fill; + input += fill; + ilen -= fill; + + if( ctx->left == 16 ) + { + ctx->left = 0; + md2_process( ctx ); + } + } +} + +/* + * MD2 final digest + */ +void md2_finish( md2_context *ctx, unsigned char output[16] ) +{ + size_t i; + unsigned char x; + + x = (unsigned char)( 16 - ctx->left ); + + for( i = ctx->left; i < 16; i++ ) + ctx->buffer[i] = x; + + md2_process( ctx ); + + memcpy( ctx->buffer, ctx->cksum, 16 ); + md2_process( ctx ); + + memcpy( output, ctx->state, 16 ); +} + +#endif /* !POLARSSL_MD2_ALT */ + +/* + * output = MD2( input buffer ) + */ +void md2( const unsigned char *input, size_t ilen, unsigned char output[16] ) +{ + md2_context ctx; + + md2_starts( &ctx ); + md2_update( &ctx, input, ilen ); + md2_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( md2_context ) ); +} + +#if defined(POLARSSL_FS_IO) +/* + * output = MD2( file contents ) + */ +int md2_file( const char *path, unsigned char output[16] ) +{ + FILE *f; + size_t n; + md2_context ctx; + unsigned char buf[1024]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_MD2_FILE_IO_ERROR ); + + md2_starts( &ctx ); + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + md2_update( &ctx, buf, n ); + + md2_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( md2_context ) ); + + if( ferror( f ) != 0 ) + { + fclose( f ); + return( POLARSSL_ERR_MD2_FILE_IO_ERROR ); + } + + fclose( f ); + return( 0 ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * MD2 HMAC context setup + */ +void md2_hmac_starts( md2_context *ctx, const unsigned char *key, size_t keylen ) +{ + size_t i; + unsigned char sum[16]; + + if( keylen > 16 ) + { + md2( key, keylen, sum ); + keylen = 16; + key = sum; + } + + memset( ctx->ipad, 0x36, 16 ); + memset( ctx->opad, 0x5C, 16 ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + md2_starts( ctx ); + md2_update( ctx, ctx->ipad, 16 ); + + memset( sum, 0, sizeof( sum ) ); +} + +/* + * MD2 HMAC process buffer + */ +void md2_hmac_update( md2_context *ctx, const unsigned char *input, size_t ilen ) +{ + md2_update( ctx, input, ilen ); +} + +/* + * MD2 HMAC final digest + */ +void md2_hmac_finish( md2_context *ctx, unsigned char output[16] ) +{ + unsigned char tmpbuf[16]; + + md2_finish( ctx, tmpbuf ); + md2_starts( ctx ); + md2_update( ctx, ctx->opad, 16 ); + md2_update( ctx, tmpbuf, 16 ); + md2_finish( ctx, output ); + + memset( tmpbuf, 0, sizeof( tmpbuf ) ); +} + +/* + * MD2 HMAC context reset + */ +void md2_hmac_reset( md2_context *ctx ) +{ + md2_starts( ctx ); + md2_update( ctx, ctx->ipad, 16 ); +} + +/* + * output = HMAC-MD2( hmac key, input buffer ) + */ +void md2_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[16] ) +{ + md2_context ctx; + + md2_hmac_starts( &ctx, key, keylen ); + md2_hmac_update( &ctx, input, ilen ); + md2_hmac_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( md2_context ) ); +} + +#if defined(POLARSSL_SELF_TEST) + +/* + * RFC 1319 test vectors + */ +static const char md2_test_str[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" \ + "345678901234567890" } +}; + +static const unsigned char md2_test_sum[7][16] = +{ + { 0x83, 0x50, 0xE5, 0xA3, 0xE2, 0x4C, 0x15, 0x3D, + 0xF2, 0x27, 0x5C, 0x9F, 0x80, 0x69, 0x27, 0x73 }, + { 0x32, 0xEC, 0x01, 0xEC, 0x4A, 0x6D, 0xAC, 0x72, + 0xC0, 0xAB, 0x96, 0xFB, 0x34, 0xC0, 0xB5, 0xD1 }, + { 0xDA, 0x85, 0x3B, 0x0D, 0x3F, 0x88, 0xD9, 0x9B, + 0x30, 0x28, 0x3A, 0x69, 0xE6, 0xDE, 0xD6, 0xBB }, + { 0xAB, 0x4F, 0x49, 0x6B, 0xFB, 0x2A, 0x53, 0x0B, + 0x21, 0x9F, 0xF3, 0x30, 0x31, 0xFE, 0x06, 0xB0 }, + { 0x4E, 0x8D, 0xDF, 0xF3, 0x65, 0x02, 0x92, 0xAB, + 0x5A, 0x41, 0x08, 0xC3, 0xAA, 0x47, 0x94, 0x0B }, + { 0xDA, 0x33, 0xDE, 0xF2, 0xA4, 0x2D, 0xF1, 0x39, + 0x75, 0x35, 0x28, 0x46, 0xC3, 0x03, 0x38, 0xCD }, + { 0xD5, 0x97, 0x6F, 0x79, 0xD8, 0x3D, 0x3A, 0x0D, + 0xC9, 0x80, 0x6C, 0x3C, 0x66, 0xF3, 0xEF, 0xD8 } +}; + +/* + * Checkup routine + */ +int md2_self_test( int verbose ) +{ + int i; + unsigned char md2sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + printf( " MD2 test #%d: ", i + 1 ); + + md2( (unsigned char *) md2_test_str[i], + strlen( md2_test_str[i] ), md2sum ); + + if( memcmp( md2sum, md2_test_sum[i], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/md2.h b/src/libpolarssl/md2.h new file mode 100644 index 0000000..94f19fc --- /dev/null +++ b/src/libpolarssl/md2.h @@ -0,0 +1,171 @@ +/** + * \file md2.h + * + * \brief MD2 message digest algorithm (hash function) + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_MD2_H +#define POLARSSL_MD2_H + +#include "config.h" + +#include + +#define POLARSSL_ERR_MD2_FILE_IO_ERROR -0x0070 /**< Read/write error in file. */ + +#if !defined(POLARSSL_MD2_ALT) +// Regular implementation +// + +/** + * \brief MD2 context structure + */ +typedef struct +{ + unsigned char cksum[16]; /*!< checksum of the data block */ + unsigned char state[48]; /*!< intermediate digest state */ + unsigned char buffer[16]; /*!< data block being processed */ + + unsigned char ipad[16]; /*!< HMAC: inner padding */ + unsigned char opad[16]; /*!< HMAC: outer padding */ + size_t left; /*!< amount of data in buffer */ +} +md2_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD2 context setup + * + * \param ctx context to be initialized + */ +void md2_starts( md2_context *ctx ); + +/** + * \brief MD2 process buffer + * + * \param ctx MD2 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md2_update( md2_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD2 final digest + * + * \param ctx MD2 context + * \param output MD2 checksum result + */ +void md2_finish( md2_context *ctx, unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_MD2_ALT */ +#include "md2_alt.h" +#endif /* POLARSSL_MD2_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = MD2( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD2 checksum result + */ +void md2( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Output = MD2( file contents ) + * + * \param path input file name + * \param output MD2 checksum result + * + * \return 0 if successful, or POLARSSL_ERR_MD2_FILE_IO_ERROR + */ +int md2_file( const char *path, unsigned char output[16] ); + +/** + * \brief MD2 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void md2_hmac_starts( md2_context *ctx, const unsigned char *key, size_t keylen ); + +/** + * \brief MD2 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md2_hmac_update( md2_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD2 HMAC final digest + * + * \param ctx HMAC context + * \param output MD2 HMAC checksum result + */ +void md2_hmac_finish( md2_context *ctx, unsigned char output[16] ); + +/** + * \brief MD2 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void md2_hmac_reset( md2_context *ctx ); + +/** + * \brief Output = HMAC-MD2( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-MD2 result + */ +void md2_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int md2_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* md2.h */ diff --git a/src/libpolarssl/md4.c b/src/libpolarssl/md4.c new file mode 100644 index 0000000..99929f5 --- /dev/null +++ b/src/libpolarssl/md4.c @@ -0,0 +1,464 @@ +/* + * RFC 1186/1320 compliant MD4 implementation + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The MD4 algorithm was designed by Ron Rivest in 1990. + * + * http://www.ietf.org/rfc/rfc1186.txt + * http://www.ietf.org/rfc/rfc1320.txt + */ + +#include "config.h" + +#if defined(POLARSSL_MD4_C) + +#include "md4.h" + +#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST) +#include +#endif + +#if !defined(POLARSSL_MD4_ALT) + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ +} +#endif + +/* + * MD4 context setup + */ +void md4_starts( md4_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +static void md4_process( md4_context *ctx, const unsigned char data[64] ) +{ + uint32_t X[16], A, B, C, D; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x, y, z) ((x & y) | ((~x) & z)) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 1], 7 ); + P( C, D, A, B, X[ 2], 11 ); + P( B, C, D, A, X[ 3], 19 ); + P( A, B, C, D, X[ 4], 3 ); + P( D, A, B, C, X[ 5], 7 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[ 7], 19 ); + P( A, B, C, D, X[ 8], 3 ); + P( D, A, B, C, X[ 9], 7 ); + P( C, D, A, B, X[10], 11 ); + P( B, C, D, A, X[11], 19 ); + P( A, B, C, D, X[12], 3 ); + P( D, A, B, C, X[13], 7 ); + P( C, D, A, B, X[14], 11 ); + P( B, C, D, A, X[15], 19 ); + +#undef P +#undef F + +#define F(x,y,z) ((x & y) | (x & z) | (y & z)) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 4], 5 ); + P( C, D, A, B, X[ 8], 9 ); + P( B, C, D, A, X[12], 13 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 5], 5 ); + P( C, D, A, B, X[ 9], 9 ); + P( B, C, D, A, X[13], 13 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[ 6], 5 ); + P( C, D, A, B, X[10], 9 ); + P( B, C, D, A, X[14], 13 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[ 7], 5 ); + P( C, D, A, B, X[11], 9 ); + P( B, C, D, A, X[15], 13 ); + +#undef P +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 8], 9 ); + P( C, D, A, B, X[ 4], 11 ); + P( B, C, D, A, X[12], 15 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[10], 9 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[14], 15 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 9], 9 ); + P( C, D, A, B, X[ 5], 11 ); + P( B, C, D, A, X[13], 15 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[11], 9 ); + P( C, D, A, B, X[ 7], 11 ); + P( B, C, D, A, X[15], 15 ); + +#undef F +#undef P + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} + +/* + * MD4 process buffer + */ +void md4_update( md4_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, fill ); + md4_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + md4_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, ilen ); + } +} + +static const unsigned char md4_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD4 final digest + */ +void md4_finish( md4_context *ctx, unsigned char output[16] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, msglen, 0 ); + PUT_UINT32_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + md4_update( ctx, (unsigned char *) md4_padding, padn ); + md4_update( ctx, msglen, 8 ); + + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); +} + +#endif /* !POLARSSL_MD4_ALT */ + +/* + * output = MD4( input buffer ) + */ +void md4( const unsigned char *input, size_t ilen, unsigned char output[16] ) +{ + md4_context ctx; + + md4_starts( &ctx ); + md4_update( &ctx, input, ilen ); + md4_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( md4_context ) ); +} + +#if defined(POLARSSL_FS_IO) +/* + * output = MD4( file contents ) + */ +int md4_file( const char *path, unsigned char output[16] ) +{ + FILE *f; + size_t n; + md4_context ctx; + unsigned char buf[1024]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_MD4_FILE_IO_ERROR ); + + md4_starts( &ctx ); + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + md4_update( &ctx, buf, n ); + + md4_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( md4_context ) ); + + if( ferror( f ) != 0 ) + { + fclose( f ); + return( POLARSSL_ERR_MD4_FILE_IO_ERROR ); + } + + fclose( f ); + return( 0 ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * MD4 HMAC context setup + */ +void md4_hmac_starts( md4_context *ctx, const unsigned char *key, size_t keylen ) +{ + size_t i; + unsigned char sum[16]; + + if( keylen > 64 ) + { + md4( key, keylen, sum ); + keylen = 16; + key = sum; + } + + memset( ctx->ipad, 0x36, 64 ); + memset( ctx->opad, 0x5C, 64 ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + md4_starts( ctx ); + md4_update( ctx, ctx->ipad, 64 ); + + memset( sum, 0, sizeof( sum ) ); +} + +/* + * MD4 HMAC process buffer + */ +void md4_hmac_update( md4_context *ctx, const unsigned char *input, size_t ilen ) +{ + md4_update( ctx, input, ilen ); +} + +/* + * MD4 HMAC final digest + */ +void md4_hmac_finish( md4_context *ctx, unsigned char output[16] ) +{ + unsigned char tmpbuf[16]; + + md4_finish( ctx, tmpbuf ); + md4_starts( ctx ); + md4_update( ctx, ctx->opad, 64 ); + md4_update( ctx, tmpbuf, 16 ); + md4_finish( ctx, output ); + + memset( tmpbuf, 0, sizeof( tmpbuf ) ); +} + +/* + * MD4 HMAC context reset + */ +void md4_hmac_reset( md4_context *ctx ) +{ + md4_starts( ctx ); + md4_update( ctx, ctx->ipad, 64 ); +} + +/* + * output = HMAC-MD4( hmac key, input buffer ) + */ +void md4_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[16] ) +{ + md4_context ctx; + + md4_hmac_starts( &ctx, key, keylen ); + md4_hmac_update( &ctx, input, ilen ); + md4_hmac_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( md4_context ) ); +} + +#if defined(POLARSSL_SELF_TEST) + +/* + * RFC 1320 test vectors + */ +static const char md4_test_str[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" \ + "345678901234567890" } +}; + +static const unsigned char md4_test_sum[7][16] = +{ + { 0x31, 0xD6, 0xCF, 0xE0, 0xD1, 0x6A, 0xE9, 0x31, + 0xB7, 0x3C, 0x59, 0xD7, 0xE0, 0xC0, 0x89, 0xC0 }, + { 0xBD, 0xE5, 0x2C, 0xB3, 0x1D, 0xE3, 0x3E, 0x46, + 0x24, 0x5E, 0x05, 0xFB, 0xDB, 0xD6, 0xFB, 0x24 }, + { 0xA4, 0x48, 0x01, 0x7A, 0xAF, 0x21, 0xD8, 0x52, + 0x5F, 0xC1, 0x0A, 0xE8, 0x7A, 0xA6, 0x72, 0x9D }, + { 0xD9, 0x13, 0x0A, 0x81, 0x64, 0x54, 0x9F, 0xE8, + 0x18, 0x87, 0x48, 0x06, 0xE1, 0xC7, 0x01, 0x4B }, + { 0xD7, 0x9E, 0x1C, 0x30, 0x8A, 0xA5, 0xBB, 0xCD, + 0xEE, 0xA8, 0xED, 0x63, 0xDF, 0x41, 0x2D, 0xA9 }, + { 0x04, 0x3F, 0x85, 0x82, 0xF2, 0x41, 0xDB, 0x35, + 0x1C, 0xE6, 0x27, 0xE1, 0x53, 0xE7, 0xF0, 0xE4 }, + { 0xE3, 0x3B, 0x4D, 0xDC, 0x9C, 0x38, 0xF2, 0x19, + 0x9C, 0x3E, 0x7B, 0x16, 0x4F, 0xCC, 0x05, 0x36 } +}; + +/* + * Checkup routine + */ +int md4_self_test( int verbose ) +{ + int i; + unsigned char md4sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + printf( " MD4 test #%d: ", i + 1 ); + + md4( (unsigned char *) md4_test_str[i], + strlen( md4_test_str[i] ), md4sum ); + + if( memcmp( md4sum, md4_test_sum[i], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/md4.h b/src/libpolarssl/md4.h new file mode 100644 index 0000000..56fba2f --- /dev/null +++ b/src/libpolarssl/md4.h @@ -0,0 +1,177 @@ +/** + * \file md4.h + * + * \brief MD4 message digest algorithm (hash function) + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_MD4_H +#define POLARSSL_MD4_H + +#include "config.h" + +#include + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define POLARSSL_ERR_MD4_FILE_IO_ERROR -0x0072 /**< Read/write error in file. */ + +#if !defined(POLARSSL_MD4_ALT) +// Regular implementation +// + +/** + * \brief MD4 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +md4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD4 context setup + * + * \param ctx context to be initialized + */ +void md4_starts( md4_context *ctx ); + +/** + * \brief MD4 process buffer + * + * \param ctx MD4 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md4_update( md4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD4 final digest + * + * \param ctx MD4 context + * \param output MD4 checksum result + */ +void md4_finish( md4_context *ctx, unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_MD4_ALT */ +#include "md4_alt.h" +#endif /* POLARSSL_MD4_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = MD4( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD4 checksum result + */ +void md4( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Output = MD4( file contents ) + * + * \param path input file name + * \param output MD4 checksum result + * + * \return 0 if successful, or POLARSSL_ERR_MD4_FILE_IO_ERROR + */ +int md4_file( const char *path, unsigned char output[16] ); + +/** + * \brief MD4 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void md4_hmac_starts( md4_context *ctx, const unsigned char *key, size_t keylen ); + +/** + * \brief MD4 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md4_hmac_update( md4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD4 HMAC final digest + * + * \param ctx HMAC context + * \param output MD4 HMAC checksum result + */ +void md4_hmac_finish( md4_context *ctx, unsigned char output[16] ); + +/** + * \brief MD4 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void md4_hmac_reset( md4_context *ctx ); + +/** + * \brief Output = HMAC-MD4( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-MD4 result + */ +void md4_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int md4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* md4.h */ diff --git a/src/libpolarssl/md5.c b/src/libpolarssl/md5.c new file mode 100644 index 0000000..2df2ba2 --- /dev/null +++ b/src/libpolarssl/md5.c @@ -0,0 +1,585 @@ +/* + * RFC 1321 compliant MD5 implementation + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The MD5 algorithm was designed by Ron Rivest in 1991. + * + * http://www.ietf.org/rfc/rfc1321.txt + */ + +#include "config.h" + +#if defined(POLARSSL_MD5_C) + +#include "md5.h" + +#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST) +#include +#endif + +#if !defined(POLARSSL_MD5_ALT) + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ +} +#endif + +/* + * MD5 context setup + */ +void md5_starts( md5_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +void md5_process( md5_context *ctx, const unsigned char data[64] ) +{ + uint32_t X[16], A, B, C, D; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define P(a,b,c,d,k,s,t) \ +{ \ + a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) + + P( A, B, C, D, 0, 7, 0xD76AA478 ); + P( D, A, B, C, 1, 12, 0xE8C7B756 ); + P( C, D, A, B, 2, 17, 0x242070DB ); + P( B, C, D, A, 3, 22, 0xC1BDCEEE ); + P( A, B, C, D, 4, 7, 0xF57C0FAF ); + P( D, A, B, C, 5, 12, 0x4787C62A ); + P( C, D, A, B, 6, 17, 0xA8304613 ); + P( B, C, D, A, 7, 22, 0xFD469501 ); + P( A, B, C, D, 8, 7, 0x698098D8 ); + P( D, A, B, C, 9, 12, 0x8B44F7AF ); + P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); + P( B, C, D, A, 11, 22, 0x895CD7BE ); + P( A, B, C, D, 12, 7, 0x6B901122 ); + P( D, A, B, C, 13, 12, 0xFD987193 ); + P( C, D, A, B, 14, 17, 0xA679438E ); + P( B, C, D, A, 15, 22, 0x49B40821 ); + +#undef F + +#define F(x,y,z) (y ^ (z & (x ^ y))) + + P( A, B, C, D, 1, 5, 0xF61E2562 ); + P( D, A, B, C, 6, 9, 0xC040B340 ); + P( C, D, A, B, 11, 14, 0x265E5A51 ); + P( B, C, D, A, 0, 20, 0xE9B6C7AA ); + P( A, B, C, D, 5, 5, 0xD62F105D ); + P( D, A, B, C, 10, 9, 0x02441453 ); + P( C, D, A, B, 15, 14, 0xD8A1E681 ); + P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); + P( A, B, C, D, 9, 5, 0x21E1CDE6 ); + P( D, A, B, C, 14, 9, 0xC33707D6 ); + P( C, D, A, B, 3, 14, 0xF4D50D87 ); + P( B, C, D, A, 8, 20, 0x455A14ED ); + P( A, B, C, D, 13, 5, 0xA9E3E905 ); + P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); + P( C, D, A, B, 7, 14, 0x676F02D9 ); + P( B, C, D, A, 12, 20, 0x8D2A4C8A ); + +#undef F + +#define F(x,y,z) (x ^ y ^ z) + + P( A, B, C, D, 5, 4, 0xFFFA3942 ); + P( D, A, B, C, 8, 11, 0x8771F681 ); + P( C, D, A, B, 11, 16, 0x6D9D6122 ); + P( B, C, D, A, 14, 23, 0xFDE5380C ); + P( A, B, C, D, 1, 4, 0xA4BEEA44 ); + P( D, A, B, C, 4, 11, 0x4BDECFA9 ); + P( C, D, A, B, 7, 16, 0xF6BB4B60 ); + P( B, C, D, A, 10, 23, 0xBEBFBC70 ); + P( A, B, C, D, 13, 4, 0x289B7EC6 ); + P( D, A, B, C, 0, 11, 0xEAA127FA ); + P( C, D, A, B, 3, 16, 0xD4EF3085 ); + P( B, C, D, A, 6, 23, 0x04881D05 ); + P( A, B, C, D, 9, 4, 0xD9D4D039 ); + P( D, A, B, C, 12, 11, 0xE6DB99E5 ); + P( C, D, A, B, 15, 16, 0x1FA27CF8 ); + P( B, C, D, A, 2, 23, 0xC4AC5665 ); + +#undef F + +#define F(x,y,z) (y ^ (x | ~z)) + + P( A, B, C, D, 0, 6, 0xF4292244 ); + P( D, A, B, C, 7, 10, 0x432AFF97 ); + P( C, D, A, B, 14, 15, 0xAB9423A7 ); + P( B, C, D, A, 5, 21, 0xFC93A039 ); + P( A, B, C, D, 12, 6, 0x655B59C3 ); + P( D, A, B, C, 3, 10, 0x8F0CCC92 ); + P( C, D, A, B, 10, 15, 0xFFEFF47D ); + P( B, C, D, A, 1, 21, 0x85845DD1 ); + P( A, B, C, D, 8, 6, 0x6FA87E4F ); + P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); + P( C, D, A, B, 6, 15, 0xA3014314 ); + P( B, C, D, A, 13, 21, 0x4E0811A1 ); + P( A, B, C, D, 4, 6, 0xF7537E82 ); + P( D, A, B, C, 11, 10, 0xBD3AF235 ); + P( C, D, A, B, 2, 15, 0x2AD7D2BB ); + P( B, C, D, A, 9, 21, 0xEB86D391 ); + +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} + +/* + * MD5 process buffer + */ +void md5_update( md5_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + md5_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + md5_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } +} + +static const unsigned char md5_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD5 final digest + */ +void md5_finish( md5_context *ctx, unsigned char output[16] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, msglen, 0 ); + PUT_UINT32_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + md5_update( ctx, md5_padding, padn ); + md5_update( ctx, msglen, 8 ); + + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); +} + +#endif /* !POLARSSL_MD5_ALT */ + +/* + * output = MD5( input buffer ) + */ +void md5( const unsigned char *input, size_t ilen, unsigned char output[16] ) +{ + md5_context ctx; + + md5_starts( &ctx ); + md5_update( &ctx, input, ilen ); + md5_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( md5_context ) ); +} + +#if defined(POLARSSL_FS_IO) +/* + * output = MD5( file contents ) + */ +int md5_file( const char *path, unsigned char output[16] ) +{ + FILE *f; + size_t n; + md5_context ctx; + unsigned char buf[1024]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_MD5_FILE_IO_ERROR ); + + md5_starts( &ctx ); + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + md5_update( &ctx, buf, n ); + + md5_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( md5_context ) ); + + if( ferror( f ) != 0 ) + { + fclose( f ); + return( POLARSSL_ERR_MD5_FILE_IO_ERROR ); + } + + fclose( f ); + return( 0 ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * MD5 HMAC context setup + */ +void md5_hmac_starts( md5_context *ctx, const unsigned char *key, size_t keylen ) +{ + size_t i; + unsigned char sum[16]; + + if( keylen > 64 ) + { + md5( key, keylen, sum ); + keylen = 16; + key = sum; + } + + memset( ctx->ipad, 0x36, 64 ); + memset( ctx->opad, 0x5C, 64 ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + md5_starts( ctx ); + md5_update( ctx, ctx->ipad, 64 ); + + memset( sum, 0, sizeof( sum ) ); +} + +/* + * MD5 HMAC process buffer + */ +void md5_hmac_update( md5_context *ctx, const unsigned char *input, size_t ilen ) +{ + md5_update( ctx, input, ilen ); +} + +/* + * MD5 HMAC final digest + */ +void md5_hmac_finish( md5_context *ctx, unsigned char output[16] ) +{ + unsigned char tmpbuf[16]; + + md5_finish( ctx, tmpbuf ); + md5_starts( ctx ); + md5_update( ctx, ctx->opad, 64 ); + md5_update( ctx, tmpbuf, 16 ); + md5_finish( ctx, output ); + + memset( tmpbuf, 0, sizeof( tmpbuf ) ); +} + +/* + * MD5 HMAC context reset + */ +void md5_hmac_reset( md5_context *ctx ) +{ + md5_starts( ctx ); + md5_update( ctx, ctx->ipad, 64 ); +} + +/* + * output = HMAC-MD5( hmac key, input buffer ) + */ +void md5_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[16] ) +{ + md5_context ctx; + + md5_hmac_starts( &ctx, key, keylen ); + md5_hmac_update( &ctx, input, ilen ); + md5_hmac_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( md5_context ) ); +} + +#if defined(POLARSSL_SELF_TEST) +/* + * RFC 1321 test vectors + */ +static unsigned char md5_test_buf[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" \ + "345678901234567890" } +}; + +static const int md5_test_buflen[7] = +{ + 0, 1, 3, 14, 26, 62, 80 +}; + +static const unsigned char md5_test_sum[7][16] = +{ + { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, + 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E }, + { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8, + 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 }, + { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0, + 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 }, + { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D, + 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 }, + { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00, + 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B }, + { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5, + 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F }, + { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55, + 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A } +}; + +/* + * RFC 2202 test vectors + */ +static unsigned char md5_hmac_test_key[7][26] = +{ + { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" }, + { "Jefe" }, + { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" }, + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19" }, + { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" }, + { "" }, /* 0xAA 80 times */ + { "" } +}; + +static const int md5_hmac_test_keylen[7] = +{ + 16, 4, 16, 25, 16, 80, 80 +}; + +static unsigned char md5_hmac_test_buf[7][74] = +{ + { "Hi There" }, + { "what do ya want for nothing?" }, + { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" }, + { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" }, + { "Test With Truncation" }, + { "Test Using Larger Than Block-Size Key - Hash Key First" }, + { "Test Using Larger Than Block-Size Key and Larger" + " Than One Block-Size Data" } +}; + +static const int md5_hmac_test_buflen[7] = +{ + 8, 28, 50, 50, 20, 54, 73 +}; + +static const unsigned char md5_hmac_test_sum[7][16] = +{ + { 0x92, 0x94, 0x72, 0x7A, 0x36, 0x38, 0xBB, 0x1C, + 0x13, 0xF4, 0x8E, 0xF8, 0x15, 0x8B, 0xFC, 0x9D }, + { 0x75, 0x0C, 0x78, 0x3E, 0x6A, 0xB0, 0xB5, 0x03, + 0xEA, 0xA8, 0x6E, 0x31, 0x0A, 0x5D, 0xB7, 0x38 }, + { 0x56, 0xBE, 0x34, 0x52, 0x1D, 0x14, 0x4C, 0x88, + 0xDB, 0xB8, 0xC7, 0x33, 0xF0, 0xE8, 0xB3, 0xF6 }, + { 0x69, 0x7E, 0xAF, 0x0A, 0xCA, 0x3A, 0x3A, 0xEA, + 0x3A, 0x75, 0x16, 0x47, 0x46, 0xFF, 0xAA, 0x79 }, + { 0x56, 0x46, 0x1E, 0xF2, 0x34, 0x2E, 0xDC, 0x00, + 0xF9, 0xBA, 0xB9, 0x95 }, + { 0x6B, 0x1A, 0xB7, 0xFE, 0x4B, 0xD7, 0xBF, 0x8F, + 0x0B, 0x62, 0xE6, 0xCE, 0x61, 0xB9, 0xD0, 0xCD }, + { 0x6F, 0x63, 0x0F, 0xAD, 0x67, 0xCD, 0xA0, 0xEE, + 0x1F, 0xB1, 0xF5, 0x62, 0xDB, 0x3A, 0xA5, 0x3E } +}; + +/* + * Checkup routine + */ +int md5_self_test( int verbose ) +{ + int i, buflen; + unsigned char buf[1024]; + unsigned char md5sum[16]; + md5_context ctx; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + printf( " MD5 test #%d: ", i + 1 ); + + md5( md5_test_buf[i], md5_test_buflen[i], md5sum ); + + if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + printf( " HMAC-MD5 test #%d: ", i + 1 ); + + if( i == 5 || i == 6 ) + { + memset( buf, '\xAA', buflen = 80 ); + md5_hmac_starts( &ctx, buf, buflen ); + } + else + md5_hmac_starts( &ctx, md5_hmac_test_key[i], + md5_hmac_test_keylen[i] ); + + md5_hmac_update( &ctx, md5_hmac_test_buf[i], + md5_hmac_test_buflen[i] ); + + md5_hmac_finish( &ctx, md5sum ); + + buflen = ( i == 4 ) ? 12 : 16; + + if( memcmp( md5sum, md5_hmac_test_sum[i], buflen ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/md5.h b/src/libpolarssl/md5.h new file mode 100644 index 0000000..c90789d --- /dev/null +++ b/src/libpolarssl/md5.h @@ -0,0 +1,182 @@ +/** + * \file md5.h + * + * \brief MD5 message digest algorithm (hash function) + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_MD5_H +#define POLARSSL_MD5_H + +#include "config.h" + +#include + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define POLARSSL_ERR_MD5_FILE_IO_ERROR -0x0074 /**< Read/write error in file. */ + +#if !defined(POLARSSL_MD5_ALT) +// Regular implementation +// + +/** + * \brief MD5 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +md5_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + */ +void md5_starts( md5_context *ctx ); + +/** + * \brief MD5 process buffer + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md5_update( md5_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + */ +void md5_finish( md5_context *ctx, unsigned char output[16] ); + +/* Internal use */ +void md5_process( md5_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_MD5_ALT */ +#include "md5_alt.h" +#endif /* POLARSSL_MD5_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + */ +void md5( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Output = MD5( file contents ) + * + * \param path input file name + * \param output MD5 checksum result + * + * \return 0 if successful, or POLARSSL_ERR_MD5_FILE_IO_ERROR + */ +int md5_file( const char *path, unsigned char output[16] ); + +/** + * \brief MD5 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void md5_hmac_starts( md5_context *ctx, + const unsigned char *key, size_t keylen ); + +/** + * \brief MD5 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void md5_hmac_update( md5_context *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief MD5 HMAC final digest + * + * \param ctx HMAC context + * \param output MD5 HMAC checksum result + */ +void md5_hmac_finish( md5_context *ctx, unsigned char output[16] ); + +/** + * \brief MD5 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void md5_hmac_reset( md5_context *ctx ); + +/** + * \brief Output = HMAC-MD5( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-MD5 result + */ +void md5_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int md5_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* md5.h */ diff --git a/src/libpolarssl/md_wrap.c b/src/libpolarssl/md_wrap.c new file mode 100644 index 0000000..38bb2f9 --- /dev/null +++ b/src/libpolarssl/md_wrap.c @@ -0,0 +1,733 @@ +/** + * \file md_wrap.c + + * \brief Generic message digest wrapper for PolarSSL + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_MD_C) + +#include "md_wrap.h" + +#if defined(POLARSSL_MD2_C) +#include "md2.h" +#endif + +#if defined(POLARSSL_MD4_C) +#include "md4.h" +#endif + +#if defined(POLARSSL_MD5_C) +#include "md5.h" +#endif + +#if defined(POLARSSL_SHA1_C) +#include "sha1.h" +#endif + +#if defined(POLARSSL_SHA2_C) +#include "sha2.h" +#endif + +#if defined(POLARSSL_SHA4_C) +#include "sha4.h" +#endif + +#include + +#if defined(POLARSSL_MD2_C) + +static void md2_starts_wrap( void *ctx ) +{ + md2_starts( (md2_context *) ctx ); +} + +static void md2_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + md2_update( (md2_context *) ctx, input, ilen ); +} + +static void md2_finish_wrap( void *ctx, unsigned char *output ) +{ + md2_finish( (md2_context *) ctx, output ); +} + +int md2_file_wrap( const char *path, unsigned char *output ) +{ +#if defined(POLARSSL_FS_IO) + return md2_file( path, output ); +#else + ((void) path); + ((void) output); + return POLARSSL_ERR_MD_FEATURE_UNAVAILABLE; +#endif +} + +static void md2_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen ) +{ + md2_hmac_starts( (md2_context *) ctx, key, keylen ); +} + +static void md2_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + md2_hmac_update( (md2_context *) ctx, input, ilen ); +} + +static void md2_hmac_finish_wrap( void *ctx, unsigned char *output ) +{ + md2_hmac_finish( (md2_context *) ctx, output ); +} + +static void md2_hmac_reset_wrap( void *ctx ) +{ + md2_hmac_reset( (md2_context *) ctx ); +} + +static void * md2_ctx_alloc( void ) +{ + return malloc( sizeof( md2_context ) ); +} + +static void md2_ctx_free( void *ctx ) +{ + free( ctx ); +} + +const md_info_t md2_info = { + POLARSSL_MD_MD2, + "MD2", + 16, + md2_starts_wrap, + md2_update_wrap, + md2_finish_wrap, + md2, + md2_file_wrap, + md2_hmac_starts_wrap, + md2_hmac_update_wrap, + md2_hmac_finish_wrap, + md2_hmac_reset_wrap, + md2_hmac, + md2_ctx_alloc, + md2_ctx_free, +}; + +#endif + +#if defined(POLARSSL_MD4_C) + +void md4_starts_wrap( void *ctx ) +{ + md4_starts( (md4_context *) ctx ); +} + +void md4_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + md4_update( (md4_context *) ctx, input, ilen ); +} + +void md4_finish_wrap( void *ctx, unsigned char *output ) +{ + md4_finish( (md4_context *) ctx, output ); +} + +int md4_file_wrap( const char *path, unsigned char *output ) +{ +#if defined(POLARSSL_FS_IO) + return md4_file( path, output ); +#else + ((void) path); + ((void) output); + return POLARSSL_ERR_MD_FEATURE_UNAVAILABLE; +#endif +} + +void md4_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen ) +{ + md4_hmac_starts( (md4_context *) ctx, key, keylen ); +} + +void md4_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + md4_hmac_update( (md4_context *) ctx, input, ilen ); +} + +void md4_hmac_finish_wrap( void *ctx, unsigned char *output ) +{ + md4_hmac_finish( (md4_context *) ctx, output ); +} + +void md4_hmac_reset_wrap( void *ctx ) +{ + md4_hmac_reset( (md4_context *) ctx ); +} + +void *md4_ctx_alloc( void ) +{ + return malloc( sizeof( md4_context ) ); +} + +void md4_ctx_free( void *ctx ) +{ + free( ctx ); +} + +const md_info_t md4_info = { + POLARSSL_MD_MD4, + "MD4", + 16, + md4_starts_wrap, + md4_update_wrap, + md4_finish_wrap, + md4, + md4_file_wrap, + md4_hmac_starts_wrap, + md4_hmac_update_wrap, + md4_hmac_finish_wrap, + md4_hmac_reset_wrap, + md4_hmac, + md4_ctx_alloc, + md4_ctx_free, +}; + +#endif + +#if defined(POLARSSL_MD5_C) + +static void md5_starts_wrap( void *ctx ) +{ + md5_starts( (md5_context *) ctx ); +} + +static void md5_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + md5_update( (md5_context *) ctx, input, ilen ); +} + +static void md5_finish_wrap( void *ctx, unsigned char *output ) +{ + md5_finish( (md5_context *) ctx, output ); +} + +int md5_file_wrap( const char *path, unsigned char *output ) +{ +#if defined(POLARSSL_FS_IO) + return md5_file( path, output ); +#else + ((void) path); + ((void) output); + return POLARSSL_ERR_MD_FEATURE_UNAVAILABLE; +#endif +} + +static void md5_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen ) +{ + md5_hmac_starts( (md5_context *) ctx, key, keylen ); +} + +static void md5_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + md5_hmac_update( (md5_context *) ctx, input, ilen ); +} + +static void md5_hmac_finish_wrap( void *ctx, unsigned char *output ) +{ + md5_hmac_finish( (md5_context *) ctx, output ); +} + +static void md5_hmac_reset_wrap( void *ctx ) +{ + md5_hmac_reset( (md5_context *) ctx ); +} + +static void * md5_ctx_alloc( void ) +{ + return malloc( sizeof( md5_context ) ); +} + +static void md5_ctx_free( void *ctx ) +{ + free( ctx ); +} + +const md_info_t md5_info = { + POLARSSL_MD_MD5, + "MD5", + 16, + md5_starts_wrap, + md5_update_wrap, + md5_finish_wrap, + md5, + md5_file_wrap, + md5_hmac_starts_wrap, + md5_hmac_update_wrap, + md5_hmac_finish_wrap, + md5_hmac_reset_wrap, + md5_hmac, + md5_ctx_alloc, + md5_ctx_free, +}; + +#endif + +#if defined(POLARSSL_SHA1_C) + +void sha1_starts_wrap( void *ctx ) +{ + sha1_starts( (sha1_context *) ctx ); +} + +void sha1_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + sha1_update( (sha1_context *) ctx, input, ilen ); +} + +void sha1_finish_wrap( void *ctx, unsigned char *output ) +{ + sha1_finish( (sha1_context *) ctx, output ); +} + +int sha1_file_wrap( const char *path, unsigned char *output ) +{ +#if defined(POLARSSL_FS_IO) + return sha1_file( path, output ); +#else + ((void) path); + ((void) output); + return POLARSSL_ERR_MD_FEATURE_UNAVAILABLE; +#endif +} + +void sha1_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen ) +{ + sha1_hmac_starts( (sha1_context *) ctx, key, keylen ); +} + +void sha1_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + sha1_hmac_update( (sha1_context *) ctx, input, ilen ); +} + +void sha1_hmac_finish_wrap( void *ctx, unsigned char *output ) +{ + sha1_hmac_finish( (sha1_context *) ctx, output ); +} + +void sha1_hmac_reset_wrap( void *ctx ) +{ + sha1_hmac_reset( (sha1_context *) ctx ); +} + +void * sha1_ctx_alloc( void ) +{ + return malloc( sizeof( sha1_context ) ); +} + +void sha1_ctx_free( void *ctx ) +{ + free( ctx ); +} + +const md_info_t sha1_info = { + POLARSSL_MD_SHA1, + "SHA1", + 20, + sha1_starts_wrap, + sha1_update_wrap, + sha1_finish_wrap, + sha1, + sha1_file_wrap, + sha1_hmac_starts_wrap, + sha1_hmac_update_wrap, + sha1_hmac_finish_wrap, + sha1_hmac_reset_wrap, + sha1_hmac, + sha1_ctx_alloc, + sha1_ctx_free, +}; + +#endif + +/* + * Wrappers for generic message digests + */ +#if defined(POLARSSL_SHA2_C) + +void sha224_starts_wrap( void *ctx ) +{ + sha2_starts( (sha2_context *) ctx, 1 ); +} + +void sha224_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + sha2_update( (sha2_context *) ctx, input, ilen ); +} + +void sha224_finish_wrap( void *ctx, unsigned char *output ) +{ + sha2_finish( (sha2_context *) ctx, output ); +} + +void sha224_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + sha2( input, ilen, output, 1 ); +} + +int sha224_file_wrap( const char *path, unsigned char *output ) +{ +#if defined(POLARSSL_FS_IO) + return sha2_file( path, output, 1 ); +#else + ((void) path); + ((void) output); + return POLARSSL_ERR_MD_FEATURE_UNAVAILABLE; +#endif +} + +void sha224_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen ) +{ + sha2_hmac_starts( (sha2_context *) ctx, key, keylen, 1 ); +} + +void sha224_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + sha2_hmac_update( (sha2_context *) ctx, input, ilen ); +} + +void sha224_hmac_finish_wrap( void *ctx, unsigned char *output ) +{ + sha2_hmac_finish( (sha2_context *) ctx, output ); +} + +void sha224_hmac_reset_wrap( void *ctx ) +{ + sha2_hmac_reset( (sha2_context *) ctx ); +} + +void sha224_hmac_wrap( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + sha2_hmac( key, keylen, input, ilen, output, 1 ); +} + +void * sha224_ctx_alloc( void ) +{ + return malloc( sizeof( sha2_context ) ); +} + +void sha224_ctx_free( void *ctx ) +{ + free( ctx ); +} + +const md_info_t sha224_info = { + POLARSSL_MD_SHA224, + "SHA224", + 28, + sha224_starts_wrap, + sha224_update_wrap, + sha224_finish_wrap, + sha224_wrap, + sha224_file_wrap, + sha224_hmac_starts_wrap, + sha224_hmac_update_wrap, + sha224_hmac_finish_wrap, + sha224_hmac_reset_wrap, + sha224_hmac_wrap, + sha224_ctx_alloc, + sha224_ctx_free, +}; + +void sha256_starts_wrap( void *ctx ) +{ + sha2_starts( (sha2_context *) ctx, 0 ); +} + +void sha256_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + sha2_update( (sha2_context *) ctx, input, ilen ); +} + +void sha256_finish_wrap( void *ctx, unsigned char *output ) +{ + sha2_finish( (sha2_context *) ctx, output ); +} + +void sha256_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + sha2( input, ilen, output, 0 ); +} + +int sha256_file_wrap( const char *path, unsigned char *output ) +{ +#if defined(POLARSSL_FS_IO) + return sha2_file( path, output, 0 ); +#else + ((void) path); + ((void) output); + return POLARSSL_ERR_MD_FEATURE_UNAVAILABLE; +#endif +} + +void sha256_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen ) +{ + sha2_hmac_starts( (sha2_context *) ctx, key, keylen, 0 ); +} + +void sha256_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + sha2_hmac_update( (sha2_context *) ctx, input, ilen ); +} + +void sha256_hmac_finish_wrap( void *ctx, unsigned char *output ) +{ + sha2_hmac_finish( (sha2_context *) ctx, output ); +} + +void sha256_hmac_reset_wrap( void *ctx ) +{ + sha2_hmac_reset( (sha2_context *) ctx ); +} + +void sha256_hmac_wrap( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + sha2_hmac( key, keylen, input, ilen, output, 0 ); +} + +void * sha256_ctx_alloc( void ) +{ + return malloc( sizeof( sha2_context ) ); +} + +void sha256_ctx_free( void *ctx ) +{ + free( ctx ); +} + +const md_info_t sha256_info = { + POLARSSL_MD_SHA256, + "SHA256", + 32, + sha256_starts_wrap, + sha256_update_wrap, + sha256_finish_wrap, + sha256_wrap, + sha256_file_wrap, + sha256_hmac_starts_wrap, + sha256_hmac_update_wrap, + sha256_hmac_finish_wrap, + sha256_hmac_reset_wrap, + sha256_hmac_wrap, + sha256_ctx_alloc, + sha256_ctx_free, +}; + +#endif + +#if defined(POLARSSL_SHA4_C) + +void sha384_starts_wrap( void *ctx ) +{ + sha4_starts( (sha4_context *) ctx, 1 ); +} + +void sha384_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + sha4_update( (sha4_context *) ctx, input, ilen ); +} + +void sha384_finish_wrap( void *ctx, unsigned char *output ) +{ + sha4_finish( (sha4_context *) ctx, output ); +} + +void sha384_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + sha4( input, ilen, output, 1 ); +} + +int sha384_file_wrap( const char *path, unsigned char *output ) +{ +#if defined(POLARSSL_FS_IO) + return sha4_file( path, output, 1 ); +#else + ((void) path); + ((void) output); + return POLARSSL_ERR_MD_FEATURE_UNAVAILABLE; +#endif +} + +void sha384_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen ) +{ + sha4_hmac_starts( (sha4_context *) ctx, key, keylen, 1 ); +} + +void sha384_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + sha4_hmac_update( (sha4_context *) ctx, input, ilen ); +} + +void sha384_hmac_finish_wrap( void *ctx, unsigned char *output ) +{ + sha4_hmac_finish( (sha4_context *) ctx, output ); +} + +void sha384_hmac_reset_wrap( void *ctx ) +{ + sha4_hmac_reset( (sha4_context *) ctx ); +} + +void sha384_hmac_wrap( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + sha4_hmac( key, keylen, input, ilen, output, 1 ); +} + +void * sha384_ctx_alloc( void ) +{ + return malloc( sizeof( sha4_context ) ); +} + +void sha384_ctx_free( void *ctx ) +{ + free( ctx ); +} + +const md_info_t sha384_info = { + POLARSSL_MD_SHA384, + "SHA384", + 48, + sha384_starts_wrap, + sha384_update_wrap, + sha384_finish_wrap, + sha384_wrap, + sha384_file_wrap, + sha384_hmac_starts_wrap, + sha384_hmac_update_wrap, + sha384_hmac_finish_wrap, + sha384_hmac_reset_wrap, + sha384_hmac_wrap, + sha384_ctx_alloc, + sha384_ctx_free, +}; + +void sha512_starts_wrap( void *ctx ) +{ + sha4_starts( (sha4_context *) ctx, 0 ); +} + +void sha512_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + sha4_update( (sha4_context *) ctx, input, ilen ); +} + +void sha512_finish_wrap( void *ctx, unsigned char *output ) +{ + sha4_finish( (sha4_context *) ctx, output ); +} + +void sha512_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + sha4( input, ilen, output, 0 ); +} + +int sha512_file_wrap( const char *path, unsigned char *output ) +{ +#if defined(POLARSSL_FS_IO) + return sha4_file( path, output, 0 ); +#else + ((void) path); + ((void) output); + return POLARSSL_ERR_MD_FEATURE_UNAVAILABLE; +#endif +} + +void sha512_hmac_starts_wrap( void *ctx, const unsigned char *key, size_t keylen ) +{ + sha4_hmac_starts( (sha4_context *) ctx, key, keylen, 0 ); +} + +void sha512_hmac_update_wrap( void *ctx, const unsigned char *input, size_t ilen ) +{ + sha4_hmac_update( (sha4_context *) ctx, input, ilen ); +} + +void sha512_hmac_finish_wrap( void *ctx, unsigned char *output ) +{ + sha4_hmac_finish( (sha4_context *) ctx, output ); +} + +void sha512_hmac_reset_wrap( void *ctx ) +{ + sha4_hmac_reset( (sha4_context *) ctx ); +} + +void sha512_hmac_wrap( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + sha4_hmac( key, keylen, input, ilen, output, 0 ); +} + +void * sha512_ctx_alloc( void ) +{ + return malloc( sizeof( sha4_context ) ); +} + +void sha512_ctx_free( void *ctx ) +{ + free( ctx ); +} + +const md_info_t sha512_info = { + POLARSSL_MD_SHA512, + "SHA512", + 64, + sha512_starts_wrap, + sha512_update_wrap, + sha512_finish_wrap, + sha512_wrap, + sha512_file_wrap, + sha512_hmac_starts_wrap, + sha512_hmac_update_wrap, + sha512_hmac_finish_wrap, + sha512_hmac_reset_wrap, + sha512_hmac_wrap, + sha512_ctx_alloc, + sha512_ctx_free, +}; + +#endif + +#endif diff --git a/src/libpolarssl/md_wrap.h b/src/libpolarssl/md_wrap.h new file mode 100644 index 0000000..46849d0 --- /dev/null +++ b/src/libpolarssl/md_wrap.h @@ -0,0 +1,64 @@ +/** + * \file md_wrap.h + * + * \brief Message digest wrappers. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_MD_WRAP_H +#define POLARSSL_MD_WRAP_H + +#include "config.h" +#include "md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(POLARSSL_MD2_C) +extern const md_info_t md2_info; +#endif +#if defined(POLARSSL_MD4_C) +extern const md_info_t md4_info; +#endif +#if defined(POLARSSL_MD5_C) +extern const md_info_t md5_info; +#endif +#if defined(POLARSSL_SHA1_C) +extern const md_info_t sha1_info; +#endif +#if defined(POLARSSL_SHA2_C) +extern const md_info_t sha224_info; +extern const md_info_t sha256_info; +#endif +#if defined(POLARSSL_SHA4_C) +extern const md_info_t sha384_info; +extern const md_info_t sha512_info; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* POLARSSL_MD_WRAP_H */ diff --git a/src/libpolarssl/net.c b/src/libpolarssl/net.c new file mode 100644 index 0000000..500d8b9 --- /dev/null +++ b/src/libpolarssl/net.c @@ -0,0 +1,374 @@ +/* + * TCP networking functions + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_NET_C) + +#include "net.h" + +#if defined(_WIN32) || defined(_WIN32_WCE) + +#include +#include + +#if defined(_WIN32_WCE) +#pragma comment( lib, "ws2.lib" ) +#else +#pragma comment( lib, "ws2_32.lib" ) +#endif + +#define read(fd,buf,len) recv(fd,(char*)buf,(int) len,0) +#define write(fd,buf,len) send(fd,(char*)buf,(int) len,0) +#define close(fd) closesocket(fd) + +static int wsa_init_done = 0; + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ + defined(__DragonflyBSD__) +#include +#elif defined(__APPLE__) +#include +#elif defined(sun) +#include +#else +#include +#endif + +#endif + +#include +#include +#include + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +/* + * htons() is not always available. + * By default go for LITTLE_ENDIAN variant. Otherwise hope for _BYTE_ORDER and __BIG_ENDIAN + * to help determine endianess. + */ +#if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN +#define POLARSSL_HTONS(n) (n) +#define POLARSSL_HTONL(n) (n) +#else +#define POLARSSL_HTONS(n) ((((unsigned short)(n) & 0xFF ) << 8 ) | \ + (((unsigned short)(n) & 0xFF00 ) >> 8 )) +#define POLARSSL_HTONL(n) ((((unsigned long )(n) & 0xFF ) << 24) | \ + (((unsigned long )(n) & 0xFF00 ) << 8 ) | \ + (((unsigned long )(n) & 0xFF0000 ) >> 8 ) | \ + (((unsigned long )(n) & 0xFF000000) >> 24)) +#endif + +unsigned short pssl_net_htons(unsigned short n); +unsigned long pssl_net_htonl(unsigned long n); +#define pssl_net_htons(n) POLARSSL_HTONS(n) +#define pssl_net_htonl(n) POLARSSL_HTONL(n) + +/* + * Initiate a TCP connection with host:port + */ +int pssl_net_connect( int *fd, const char *host, int port ) +{ + struct sockaddr_in server_addr; + struct hostent *server_host; + +#if defined(_WIN32) || defined(_WIN32_WCE) + WSADATA wsaData; + + if( wsa_init_done == 0 ) + { + if( WSAStartup( MAKEWORD(2,0), &wsaData ) == SOCKET_ERROR ) + return( POLARSSL_ERR_NET_SOCKET_FAILED ); + + wsa_init_done = 1; + } +#else + signal( SIGPIPE, SIG_IGN ); +#endif + + if( ( server_host = gethostbyname( host ) ) == NULL ) + return( POLARSSL_ERR_NET_UNKNOWN_HOST ); + + if( ( *fd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP ) ) < 0 ) + return( POLARSSL_ERR_NET_SOCKET_FAILED ); + + memcpy( (void *) &server_addr.sin_addr, + (void *) server_host->h_addr, + server_host->h_length ); + + server_addr.sin_family = AF_INET; + server_addr.sin_port = pssl_net_htons( port ); + + if( connect( *fd, (struct sockaddr *) &server_addr, + sizeof( server_addr ) ) < 0 ) + { + close( *fd ); + return( POLARSSL_ERR_NET_CONNECT_FAILED ); + } + + return( 0 ); +} + +/* + * Create a listening socket on bind_ip:port + */ +int pssl_net_bind( int *fd, const char *bind_ip, int port ) +{ + int n, c[4]; + struct sockaddr_in server_addr; + +#if defined(_WIN32) || defined(_WIN32_WCE) + WSADATA wsaData; + + if( wsa_init_done == 0 ) + { + if( WSAStartup( MAKEWORD(2,0), &wsaData ) == SOCKET_ERROR ) + return( POLARSSL_ERR_NET_SOCKET_FAILED ); + + wsa_init_done = 1; + } +#else + signal( SIGPIPE, SIG_IGN ); +#endif + + if( ( *fd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP ) ) < 0 ) + return( POLARSSL_ERR_NET_SOCKET_FAILED ); + + n = 1; + setsockopt( *fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) &n, sizeof( n ) ); + + server_addr.sin_addr.s_addr = pssl_net_htonl( INADDR_ANY ); + server_addr.sin_family = AF_INET; + server_addr.sin_port = pssl_net_htons( port ); + + if( bind_ip != NULL ) + { + memset( c, 0, sizeof( c ) ); + sscanf( bind_ip, "%d.%d.%d.%d", &c[0], &c[1], &c[2], &c[3] ); + + for( n = 0; n < 4; n++ ) + if( c[n] < 0 || c[n] > 255 ) + break; + + if( n == 4 ) + server_addr.sin_addr.s_addr = pssl_net_htonl( + ( (uint32_t) c[0] << 24 ) | + ( (uint32_t) c[1] << 16 ) | + ( (uint32_t) c[2] << 8 ) | + ( (uint32_t) c[3] ) ); + } + + if( bind( *fd, (struct sockaddr *) &server_addr, + sizeof( server_addr ) ) < 0 ) + { + close( *fd ); + return( POLARSSL_ERR_NET_BIND_FAILED ); + } + + if( listen( *fd, POLARSSL_NET_LISTEN_BACKLOG ) != 0 ) + { + close( *fd ); + return( POLARSSL_ERR_NET_LISTEN_FAILED ); + } + + return( 0 ); +} + +/* + * Check if the current operation is blocking + */ +static int pssl_net_is_blocking( void ) +{ +#if defined(_WIN32) || defined(_WIN32_WCE) + return( WSAGetLastError() == WSAEWOULDBLOCK ); +#else + switch( errno ) + { +#if defined EAGAIN + case EAGAIN: +#endif +#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + return( 1 ); + } + return( 0 ); +#endif +} + +/* + * Accept a connection from a remote client + */ +int pssl_net_accept( int bind_fd, int *client_fd, void *client_ip ) +{ + struct sockaddr_in client_addr; + +#if defined(__socklen_t_defined) || defined(_SOCKLEN_T) || \ + defined(_SOCKLEN_T_DECLARED) + socklen_t n = (socklen_t) sizeof( client_addr ); +#else + int n = (int) sizeof( client_addr ); +#endif + + *client_fd = accept( bind_fd, (struct sockaddr *) + &client_addr, &n ); + + if( *client_fd < 0 ) + { + if( pssl_net_is_blocking() != 0 ) + return( POLARSSL_ERR_NET_WANT_READ ); + + return( POLARSSL_ERR_NET_ACCEPT_FAILED ); + } + + if( client_ip != NULL ) + memcpy( client_ip, &client_addr.sin_addr.s_addr, + sizeof( client_addr.sin_addr.s_addr ) ); + + return( 0 ); +} + +/* + * Set the socket blocking or non-blocking + */ +int pssl_net_set_block( int fd ) +{ +#if defined(_WIN32) || defined(_WIN32_WCE) + u_long n = 0; + return( ioctlsocket( fd, FIONBIO, &n ) ); +#else + return( fcntl( fd, F_SETFL, fcntl( fd, F_GETFL ) & ~O_NONBLOCK ) ); +#endif +} + +int pssl_net_set_nonblock( int fd ) +{ +#if defined(_WIN32) || defined(_WIN32_WCE) + u_long n = 1; + return( ioctlsocket( fd, FIONBIO, &n ) ); +#else + return( fcntl( fd, F_SETFL, fcntl( fd, F_GETFL ) | O_NONBLOCK ) ); +#endif +} + +/* + * Portable usleep helper + */ +void pssl_net_usleep( unsigned long usec ) +{ + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = usec; + select( 0, NULL, NULL, NULL, &tv ); +} + +/* + * Read at most 'len' characters + */ +int pssl_net_recv( void *ctx, unsigned char *buf, size_t len ) +{ + int ret = read( *((int *) ctx), buf, len ); + + if( ret < 0 ) + { + if( pssl_net_is_blocking() != 0 ) + return( POLARSSL_ERR_NET_WANT_READ ); + +#if defined(_WIN32) || defined(_WIN32_WCE) + if( WSAGetLastError() == WSAECONNRESET ) + return( POLARSSL_ERR_NET_CONN_RESET ); +#else + if( errno == EPIPE || errno == ECONNRESET ) + return( POLARSSL_ERR_NET_CONN_RESET ); + + if( errno == EINTR ) + return( POLARSSL_ERR_NET_WANT_READ ); +#endif + + return( POLARSSL_ERR_NET_RECV_FAILED ); + } + + return( ret ); +} + +/* + * Write at most 'len' characters + */ +int pssl_net_send( void *ctx, const unsigned char *buf, size_t len ) +{ + int ret = write( *((int *) ctx), buf, len ); + + if( ret < 0 ) + { + if( pssl_net_is_blocking() != 0 ) + return( POLARSSL_ERR_NET_WANT_WRITE ); + +#if defined(_WIN32) || defined(_WIN32_WCE) + if( WSAGetLastError() == WSAECONNRESET ) + return( POLARSSL_ERR_NET_CONN_RESET ); +#else + if( errno == EPIPE || errno == ECONNRESET ) + return( POLARSSL_ERR_NET_CONN_RESET ); + + if( errno == EINTR ) + return( POLARSSL_ERR_NET_WANT_WRITE ); +#endif + + return( POLARSSL_ERR_NET_SEND_FAILED ); + } + + return( ret ); +} + +/* + * Gracefully close the connection + */ +void pssl_net_close( int fd ) +{ + shutdown( fd, 2 ); + close( fd ); +} + +#endif diff --git a/src/libpolarssl/net.h b/src/libpolarssl/net.h new file mode 100644 index 0000000..d8772ba --- /dev/null +++ b/src/libpolarssl/net.h @@ -0,0 +1,161 @@ +/** + * \file net.h + * + * \brief Network communication functions + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_NET_H +#define POLARSSL_NET_H + +#include + +#define POLARSSL_ERR_NET_UNKNOWN_HOST -0x0056 /**< Failed to get an IP address for the given hostname. */ +#define POLARSSL_ERR_NET_SOCKET_FAILED -0x0042 /**< Failed to open a socket. */ +#define POLARSSL_ERR_NET_CONNECT_FAILED -0x0044 /**< The connection to the given server / port failed. */ +#define POLARSSL_ERR_NET_BIND_FAILED -0x0046 /**< Binding of the socket failed. */ +#define POLARSSL_ERR_NET_LISTEN_FAILED -0x0048 /**< Could not listen on the socket. */ +#define POLARSSL_ERR_NET_ACCEPT_FAILED -0x004A /**< Could not accept the incoming connection. */ +#define POLARSSL_ERR_NET_RECV_FAILED -0x004C /**< Reading information from the socket failed. */ +#define POLARSSL_ERR_NET_SEND_FAILED -0x004E /**< Sending information through the socket failed. */ +#define POLARSSL_ERR_NET_CONN_RESET -0x0050 /**< Connection was reset by peer. */ +#define POLARSSL_ERR_NET_WANT_READ -0x0052 /**< Connection requires a read call. */ +#define POLARSSL_ERR_NET_WANT_WRITE -0x0054 /**< Connection requires a write call. */ + +#define POLARSSL_NET_LISTEN_BACKLOG 10 /**< The backlog that listen() should use. */ + +#if defined(POLARSSL_NET_C) +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initiate a TCP connection with host:port + * + * \param fd Socket to use + * \param host Host to connect to + * \param port Port to connect to + * + * \return 0 if successful, or one of: + * POLARSSL_ERR_NET_SOCKET_FAILED, + * POLARSSL_ERR_NET_UNKNOWN_HOST, + * POLARSSL_ERR_NET_CONNECT_FAILED + */ +int pssl_net_connect( int *fd, const char *host, int port ); + +/** + * \brief Create a listening socket on bind_ip:port. + * If bind_ip == NULL, all interfaces are binded. + * + * \param fd Socket to use + * \param bind_ip IP to bind to, can be NULL + * \param port Port number to use + * + * \return 0 if successful, or one of: + * POLARSSL_ERR_NET_SOCKET_FAILED, + * POLARSSL_ERR_NET_BIND_FAILED, + * POLARSSL_ERR_NET_LISTEN_FAILED + */ +int pssl_net_bind( int *fd, const char *bind_ip, int port ); + +/** + * \brief Accept a connection from a remote client + * + * \param bind_fd Relevant socket + * \param client_fd Will contain the connected client socket + * \param client_ip Will contain the client IP address + * + * \return 0 if successful, POLARSSL_ERR_NET_ACCEPT_FAILED, or + * POLARSSL_ERR_NET_WOULD_BLOCK is bind_fd was set to + * non-blocking and accept() is blocking. + */ +int pssl_net_accept( int bind_fd, int *client_fd, void *client_ip ); + +/** + * \brief Set the socket blocking + * + * \param fd Socket to set + * + * \return 0 if successful, or a non-zero error code + */ +int pssl_net_set_block( int fd ); + +/** + * \brief Set the socket non-blocking + * + * \param fd Socket to set + * + * \return 0 if successful, or a non-zero error code + */ +int pssl_net_set_nonblock( int fd ); + +/** + * \brief Portable usleep helper + * + * \param usec Amount of microseconds to sleep + * + * \note Real amount of time slept will not be less than + * select()'s timeout granularity (typically, 10ms). + */ +void pssl_net_usleep( unsigned long usec ); + +/** + * \brief Read at most 'len' characters. If no error occurs, + * the actual amount read is returned. + * + * \param ctx Socket + * \param buf The buffer to write to + * \param len Maximum length of the buffer + * + * \return This function returns the number of bytes received, + * or a non-zero error code; POLARSSL_ERR_NET_WANT_READ + * indicates read() is blocking. + */ +int pssl_net_recv( void *ctx, unsigned char *buf, size_t len ); + +/** + * \brief Write at most 'len' characters. If no error occurs, + * the actual amount read is returned. + * + * \param ctx Socket + * \param buf The buffer to read from + * \param len The length of the buffer + * + * \return This function returns the number of bytes sent, + * or a non-zero error code; POLARSSL_ERR_NET_WANT_WRITE + * indicates write() is blocking. + */ +int pssl_net_send( void *ctx, const unsigned char *buf, size_t len ); + +/** + * \brief Gracefully shutdown the connection + * + * \param fd The socket to close + */ +void pssl_net_close( int fd ); + +#ifdef __cplusplus +} +#endif + +#endif +#endif /* net.h */ diff --git a/src/libpolarssl/openssl.h b/src/libpolarssl/openssl.h new file mode 100644 index 0000000..62609a2 --- /dev/null +++ b/src/libpolarssl/openssl.h @@ -0,0 +1,136 @@ +/** + * \file openssl.h + * + * \brief OpenSSL wrapper (definitions, inline functions). + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * OpenSSL wrapper contributed by David Barett + */ +#ifndef POLARSSL_OPENSSL_H +#define POLARSSL_OPENSSL_H + +#include "aes.h" +#include "md5.h" +#include "rsa.h" +#include "sha1.h" + +#define AES_SIZE 16 +#define AES_BLOCK_SIZE 16 +#define AES_KEY aes_context +#define MD5_CTX md5_context +#define SHA_CTX sha1_context + +#define SHA1_Init( CTX ) \ + sha1_starts( (CTX) ) +#define SHA1_Update( CTX, BUF, LEN ) \ + sha1_update( (CTX), (unsigned char *)(BUF), (LEN) ) +#define SHA1_Final( OUT, CTX ) \ + sha1_finish( (CTX), (OUT) ) + +#define MD5_Init( CTX ) \ + md5_starts( (CTX) ) +#define MD5_Update( CTX, BUF, LEN ) \ + md5_update( (CTX), (unsigned char *)(BUF), (LEN) ) +#define MD5_Final( OUT, CTX ) \ + md5_finish( (CTX), (OUT) ) + +#define AES_set_encrypt_key( KEY, KEYSIZE, CTX ) \ + aes_setkey_enc( (CTX), (KEY), (KEYSIZE) ) +#define AES_set_decrypt_key( KEY, KEYSIZE, CTX ) \ + aes_setkey_dec( (CTX), (KEY), (KEYSIZE) ) +#define AES_cbc_encrypt( INPUT, OUTPUT, LEN, CTX, IV, MODE ) \ + aes_crypt_cbc( (CTX), (MODE), (LEN), (IV), (INPUT), (OUTPUT) ) + +/* + * RSA stuff follows. TODO: needs cleanup + */ +inline int __RSA_Passthrough( void *output, void *input, int size ) +{ + memcpy( output, input, size ); + return size; +} + +inline rsa_context* d2i_RSA_PUBKEY( void *ignore, unsigned char **bufptr, + int len ) +{ + unsigned char *buffer = *(unsigned char **) bufptr; + rsa_context *rsa; + + /* + * Not a general-purpose parser: only parses public key from *exactly* + * openssl genrsa -out privkey.pem 512 (or 1024) + * openssl rsa -in privkey.pem -out privatekey.der -outform der + * openssl rsa -in privkey.pem -out pubkey.der -outform der -pubout + * + * TODO: make a general-purpose parse + */ + if( ignore != 0 || ( len != 94 && len != 162 ) ) + return( 0 ); + + rsa = (rsa_context *) malloc( sizeof( rsa_rsa ) ); + if( rsa == NULL ) + return( 0 ); + + memset( rsa, 0, sizeof( rsa_context ) ); + + if( ( len == 94 && + mpi_read_binary( &rsa->N, &buffer[ 25], 64 ) == 0 && + mpi_read_binary( &rsa->E, &buffer[ 91], 3 ) == 0 ) || + ( len == 162 && + mpi_read_binary( &rsa->N, &buffer[ 29], 128 ) == 0 ) && + mpi_read_binary( &rsa->E, &buffer[159], 3 ) == 0 ) + { + /* + * key read successfully + */ + rsa->len = ( mpi_msb( &rsa->N ) + 7 ) >> 3; + return( rsa ); + } + else + { + memset( rsa, 0, sizeof( rsa_context ) ); + free( rsa ); + return( 0 ); + } +} + +#define RSA rsa_context +#define RSA_PKCS1_PADDING 1 /* ignored; always encrypt with this */ +#define RSA_size( CTX ) (CTX)->len +#define RSA_free( CTX ) rsa_free( CTX ) +#define ERR_get_error( ) "ERR_get_error() not supported" +#define RSA_blinding_off( IGNORE ) + +#define d2i_RSAPrivateKey( a, b, c ) new rsa_context /* TODO: C++ bleh */ + +inline int RSA_public_decrypt ( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { int outsize=size; if( !rsa_pkcs1_decrypt( key, RSA_PUBLIC, &outsize, input, output ) ) return outsize; else return -1; } +inline int RSA_private_decrypt( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { int outsize=size; if( !rsa_pkcs1_decrypt( key, RSA_PRIVATE, &outsize, input, output ) ) return outsize; else return -1; } +inline int RSA_public_encrypt ( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { if( !rsa_pkcs1_encrypt( key, RSA_PUBLIC, size, input, output ) ) return RSA_size(key); else return -1; } +inline int RSA_private_encrypt( int size, unsigned char* input, unsigned char* output, RSA* key, int ignore ) { if( !rsa_pkcs1_encrypt( key, RSA_PRIVATE, size, input, output ) ) return RSA_size(key); else return -1; } + +#ifdef __cplusplus +} +#endif + +#endif /* openssl.h */ diff --git a/src/libpolarssl/padlock.c b/src/libpolarssl/padlock.c new file mode 100644 index 0000000..a14eece --- /dev/null +++ b/src/libpolarssl/padlock.c @@ -0,0 +1,162 @@ +/* + * VIA PadLock support functions + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * This implementation is based on the VIA PadLock Programming Guide: + * + * http://www.via.com.tw/en/downloads/whitepapers/initiatives/padlock/ + * programming_guide.pdf + */ + +#include "config.h" + +#if defined(POLARSSL_PADLOCK_C) + +#include "padlock.h" + +#if defined(POLARSSL_HAVE_X86) + +/* + * PadLock detection routine + */ +int padlock_supports( int feature ) +{ + static int flags = -1; + int ebx, edx; + + if( flags == -1 ) + { + asm( "movl %%ebx, %0 \n" \ + "movl $0xC0000000, %%eax \n" \ + "cpuid \n" \ + "cmpl $0xC0000001, %%eax \n" \ + "movl $0, %%edx \n" \ + "jb unsupported \n" \ + "movl $0xC0000001, %%eax \n" \ + "cpuid \n" \ + "unsupported: \n" \ + "movl %%edx, %1 \n" \ + "movl %2, %%ebx \n" + : "=m" (ebx), "=m" (edx) + : "m" (ebx) + : "eax", "ecx", "edx" ); + + flags = edx; + } + + return( flags & feature ); +} + +/* + * PadLock AES-ECB block en(de)cryption + */ +int padlock_xcryptecb( aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int ebx; + uint32_t *rk; + uint32_t *blk; + uint32_t *ctrl; + unsigned char buf[256]; + + rk = ctx->rk; + blk = PADLOCK_ALIGN16( buf ); + memcpy( blk, input, 16 ); + + ctrl = blk + 4; + *ctrl = 0x80 | ctx->nr | ( ( ctx->nr + ( mode^1 ) - 10 ) << 9 ); + + asm( "pushfl; popfl \n" \ + "movl %%ebx, %0 \n" \ + "movl $1, %%ecx \n" \ + "movl %2, %%edx \n" \ + "movl %3, %%ebx \n" \ + "movl %4, %%esi \n" \ + "movl %4, %%edi \n" \ + ".byte 0xf3,0x0f,0xa7,0xc8\n" \ + "movl %1, %%ebx \n" + : "=m" (ebx) + : "m" (ebx), "m" (ctrl), "m" (rk), "m" (blk) + : "ecx", "edx", "esi", "edi" ); + + memcpy( output, blk, 16 ); + + return( 0 ); +} + +/* + * PadLock AES-CBC buffer en(de)cryption + */ +int padlock_xcryptcbc( aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int ebx; + size_t count; + uint32_t *rk; + uint32_t *iw; + uint32_t *ctrl; + unsigned char buf[256]; + + if( ( (long) input & 15 ) != 0 || + ( (long) output & 15 ) != 0 ) + return( POLARSSL_ERR_PADLOCK_DATA_MISALIGNED ); + + rk = ctx->rk; + iw = PADLOCK_ALIGN16( buf ); + memcpy( iw, iv, 16 ); + + ctrl = iw + 4; + *ctrl = 0x80 | ctx->nr | ( ( ctx->nr + (mode^1) - 10 ) << 9 ); + + count = (length + 15) >> 4; + + asm( "pushfl; popfl \n" \ + "movl %%ebx, %0 \n" \ + "movl %2, %%ecx \n" \ + "movl %3, %%edx \n" \ + "movl %4, %%ebx \n" \ + "movl %5, %%esi \n" \ + "movl %6, %%edi \n" \ + "movl %7, %%eax \n" \ + ".byte 0xf3,0x0f,0xa7,0xd0\n" \ + "movl %1, %%ebx \n" + : "=m" (ebx) + : "m" (ebx), "m" (count), "m" (ctrl), + "m" (rk), "m" (input), "m" (output), "m" (iw) + : "eax", "ecx", "edx", "esi", "edi" ); + + memcpy( iv, iw, 16 ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/padlock.h b/src/libpolarssl/padlock.h new file mode 100644 index 0000000..9df75cc --- /dev/null +++ b/src/libpolarssl/padlock.h @@ -0,0 +1,108 @@ +/** + * \file padlock.h + * + * \brief VIA PadLock ACE for HW encryption/decryption supported by some processors + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_PADLOCK_H +#define POLARSSL_PADLOCK_H + +#include "aes.h" + +#define POLARSSL_ERR_PADLOCK_DATA_MISALIGNED -0x0030 /**< Input data should be aligned. */ + +#if defined(POLARSSL_HAVE_ASM) && defined(__GNUC__) && defined(__i386__) + +#ifndef POLARSSL_HAVE_X86 +#define POLARSSL_HAVE_X86 +#endif + +#ifdef _MSC_VER +#include +typedef INT32 int32_t; +#else +#include +#endif + + +#define PADLOCK_RNG 0x000C +#define PADLOCK_ACE 0x00C0 +#define PADLOCK_PHE 0x0C00 +#define PADLOCK_PMM 0x3000 + +#define PADLOCK_ALIGN16(x) (uint32_t *) (16 + ((int32_t) x & ~15)) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PadLock detection routine + * + * \param The feature to detect + * + * \return 1 if CPU has support for the feature, 0 otherwise + */ +int padlock_supports( int feature ); + +/** + * \brief PadLock AES-ECB block en(de)cryption + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if success, 1 if operation failed + */ +int padlock_xcryptecb( aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief PadLock AES-CBC buffer en(de)cryption + * + * \param ctx AES context + * \param mode AES_ENCRYPT or AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if success, 1 if operation failed + */ +int padlock_xcryptcbc( aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_X86 */ + +#endif /* padlock.h */ diff --git a/src/libpolarssl/pbkdf2.c b/src/libpolarssl/pbkdf2.c new file mode 100644 index 0000000..d903767 --- /dev/null +++ b/src/libpolarssl/pbkdf2.c @@ -0,0 +1,60 @@ +/** + * \file pbkdf2.c + * + * \brief Password-Based Key Derivation Function 2 (from PKCS#5) + * DEPRECATED: Use pkcs5.c instead + * + * \author Mathias Olsson + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * PBKDF2 is part of PKCS#5 + * + * http://tools.ietf.org/html/rfc2898 (Specification) + * http://tools.ietf.org/html/rfc6070 (Test vectors) + */ + +#include "config.h" + +#if defined(POLARSSL_PBKDF2_C) + +#include "pbkdf2.h" +#include "pkcs5.h" + +int pbkdf2_hmac( md_context_t *ctx, const unsigned char *password, size_t plen, + const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output ) +{ + return pkcs5_pbkdf2_hmac( ctx, password, plen, salt, slen, iteration_count, + key_length, output ); +} + +#if defined(POLARSSL_SELF_TEST) +int pbkdf2_self_test( int verbose ) +{ + return pkcs5_self_test( verbose ); +} +#endif /* POLARSSL_SELF_TEST */ + +#endif /* POLARSSL_PBKDF2_C */ diff --git a/src/libpolarssl/pbkdf2.h b/src/libpolarssl/pbkdf2.h new file mode 100644 index 0000000..e2e61b5 --- /dev/null +++ b/src/libpolarssl/pbkdf2.h @@ -0,0 +1,82 @@ +/** + * \file pbkdf2.h + * + * \brief Password-Based Key Derivation Function 2 (from PKCS#5) + * DEPRECATED: use pkcs5.h instead. + * + * \author Mathias Olsson + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_PBKDF2_H +#define POLARSSL_PBKDF2_H + +#include + +#include "md.h" + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define POLARSSL_ERR_PBKDF2_BAD_INPUT_DATA -0x007C /**< Bad input parameters to function. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PKCS#5 PBKDF2 using HMAC + * DEPRECATED: Use pkcs5_pbkdf2_hmac() instead! + * + * \param ctx Generic HMAC context + * \param password Password to use when generating key + * \param plen Length of password + * \param salt Salt to use when generating key + * \param slen Length of salt + * \param iteration_count Iteration count + * \param key_length Length of generated key + * \param output Generated key. Must be at least as big as key_length + * + * \returns 0 on success, or a PolarSSL error code if verification fails. + */ +int pbkdf2_hmac( md_context_t *ctx, const unsigned char *password, + size_t plen, const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output ); + +/** + * \brief Checkup routine + * DEPRECATED: Use pkcs5_self_test() instead! + * + * \return 0 if successful, or 1 if the test failed + */ +int pbkdf2_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* pbkdf2.h */ diff --git a/src/libpolarssl/pem.c b/src/libpolarssl/pem.c new file mode 100644 index 0000000..dc379bc --- /dev/null +++ b/src/libpolarssl/pem.c @@ -0,0 +1,355 @@ +/* + * Privacy Enhanced Mail (PEM) decoding + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_PEM_C) + +#include "pem.h" +#include "base64.h" +#include "des.h" +#include "aes.h" +#include "md5.h" +#include "cipher.h" + +#include + +void pem_init( pem_context *ctx ) +{ + memset( ctx, 0, sizeof( pem_context ) ); +} + +#if defined(POLARSSL_MD5_C) && (defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C)) +/* + * Read a 16-byte hex string and convert it to binary + */ +static int pem_get_iv( const unsigned char *s, unsigned char *iv, size_t iv_len ) +{ + size_t i, j, k; + + memset( iv, 0, iv_len ); + + for( i = 0; i < iv_len * 2; i++, s++ ) + { + if( *s >= '0' && *s <= '9' ) j = *s - '0'; else + if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else + if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else + return( POLARSSL_ERR_PEM_INVALID_ENC_IV ); + + k = ( ( i & 1 ) != 0 ) ? j : j << 4; + + iv[i >> 1] = (unsigned char)( iv[i >> 1] | k ); + } + + return( 0 ); +} + +static void pem_pbkdf1( unsigned char *key, size_t keylen, + unsigned char *iv, + const unsigned char *pwd, size_t pwdlen ) +{ + md5_context md5_ctx; + unsigned char md5sum[16]; + size_t use_len; + + /* + * key[ 0..15] = MD5(pwd || IV) + */ + md5_starts( &md5_ctx ); + md5_update( &md5_ctx, pwd, pwdlen ); + md5_update( &md5_ctx, iv, 8 ); + md5_finish( &md5_ctx, md5sum ); + + if( keylen <= 16 ) + { + memcpy( key, md5sum, keylen ); + + memset( &md5_ctx, 0, sizeof( md5_ctx ) ); + memset( md5sum, 0, 16 ); + return; + } + + memcpy( key, md5sum, 16 ); + + /* + * key[16..23] = MD5(key[ 0..15] || pwd || IV]) + */ + md5_starts( &md5_ctx ); + md5_update( &md5_ctx, md5sum, 16 ); + md5_update( &md5_ctx, pwd, pwdlen ); + md5_update( &md5_ctx, iv, 8 ); + md5_finish( &md5_ctx, md5sum ); + + use_len = 16; + if( keylen < 32 ) + use_len = keylen - 16; + + memcpy( key + 16, md5sum, use_len ); + + memset( &md5_ctx, 0, sizeof( md5_ctx ) ); + memset( md5sum, 0, 16 ); +} + +#if defined(POLARSSL_DES_C) +/* + * Decrypt with DES-CBC, using PBKDF1 for key derivation + */ +static void pem_des_decrypt( unsigned char des_iv[8], + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + des_context des_ctx; + unsigned char des_key[8]; + + pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen ); + + des_setkey_dec( &des_ctx, des_key ); + des_crypt_cbc( &des_ctx, DES_DECRYPT, buflen, + des_iv, buf, buf ); + + memset( &des_ctx, 0, sizeof( des_ctx ) ); + memset( des_key, 0, 8 ); +} + +/* + * Decrypt with 3DES-CBC, using PBKDF1 for key derivation + */ +static void pem_des3_decrypt( unsigned char des3_iv[8], + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + des3_context des3_ctx; + unsigned char des3_key[24]; + + pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen ); + + des3_set3key_dec( &des3_ctx, des3_key ); + des3_crypt_cbc( &des3_ctx, DES_DECRYPT, buflen, + des3_iv, buf, buf ); + + memset( &des3_ctx, 0, sizeof( des3_ctx ) ); + memset( des3_key, 0, 24 ); +} +#endif /* POLARSSL_DES_C */ + +#if defined(POLARSSL_AES_C) +/* + * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation + */ +static void pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen, + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + aes_context aes_ctx; + unsigned char aes_key[32]; + + pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen ); + + aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 ); + aes_crypt_cbc( &aes_ctx, AES_DECRYPT, buflen, + aes_iv, buf, buf ); + + memset( &aes_ctx, 0, sizeof( aes_ctx ) ); + memset( aes_key, 0, keylen ); +} +#endif /* POLARSSL_AES_C */ + +#endif /* POLARSSL_MD5_C && (POLARSSL_AES_C || POLARSSL_DES_C) */ + +int pem_read_buffer( pem_context *ctx, char *header, char *footer, const unsigned char *data, const unsigned char *pwd, size_t pwdlen, size_t *use_len ) +{ + int ret, enc; + size_t len; + unsigned char *buf; + const unsigned char *s1, *s2, *end; +#if defined(POLARSSL_MD5_C) && (defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C)) + unsigned char pem_iv[16]; + cipher_type_t enc_alg = POLARSSL_CIPHER_NONE; +#else + ((void) pwd); + ((void) pwdlen); +#endif /* POLARSSL_MD5_C && (POLARSSL_AES_C || POLARSSL_DES_C) */ + + if( ctx == NULL ) + return( POLARSSL_ERR_PEM_BAD_INPUT_DATA ); + + s1 = (unsigned char *) strstr( (const char *) data, header ); + + if( s1 == NULL ) + return( POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + s2 = (unsigned char *) strstr( (const char *) data, footer ); + + if( s2 == NULL || s2 <= s1 ) + return( POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + s1 += strlen( header ); + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + end = s2; + end += strlen( footer ); + if( *end == '\r' ) end++; + if( *end == '\n' ) end++; + *use_len = end - data; + + enc = 0; + + if( memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 ) + { +#if defined(POLARSSL_MD5_C) && (defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C)) + enc++; + + s1 += 22; + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( POLARSSL_ERR_PEM_INVALID_DATA ); + + +#if defined(POLARSSL_DES_C) + if( memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 ) + { + enc_alg = POLARSSL_CIPHER_DES_EDE3_CBC; + + s1 += 23; + if( pem_get_iv( s1, pem_iv, 8 ) != 0 ) + return( POLARSSL_ERR_PEM_INVALID_ENC_IV ); + + s1 += 16; + } + else if( memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 ) + { + enc_alg = POLARSSL_CIPHER_DES_CBC; + + s1 += 18; + if( pem_get_iv( s1, pem_iv, 8) != 0 ) + return( POLARSSL_ERR_PEM_INVALID_ENC_IV ); + + s1 += 16; + } +#endif /* POLARSSL_DES_C */ + +#if defined(POLARSSL_AES_C) + if( memcmp( s1, "DEK-Info: AES-", 14 ) == 0 ) + { + if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 ) + enc_alg = POLARSSL_CIPHER_AES_128_CBC; + else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 ) + enc_alg = POLARSSL_CIPHER_AES_192_CBC; + else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 ) + enc_alg = POLARSSL_CIPHER_AES_256_CBC; + else + return( POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG ); + + s1 += 22; + if( pem_get_iv( s1, pem_iv, 16 ) != 0 ) + return( POLARSSL_ERR_PEM_INVALID_ENC_IV ); + + s1 += 32; + } +#endif /* POLARSSL_AES_C */ + + if( enc_alg == POLARSSL_CIPHER_NONE ) + return( POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG ); + + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( POLARSSL_ERR_PEM_INVALID_DATA ); +#else + return( POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE ); +#endif /* POLARSSL_MD5_C && (POLARSSL_AES_C || POLARSSL_DES_C) */ + } + + len = 0; + ret = base64_decode( NULL, &len, s1, s2 - s1 ); + + if( ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER ) + return( POLARSSL_ERR_PEM_INVALID_DATA + ret ); + + if( ( buf = (unsigned char *) malloc( len ) ) == NULL ) + return( POLARSSL_ERR_PEM_MALLOC_FAILED ); + + if( ( ret = base64_decode( buf, &len, s1, s2 - s1 ) ) != 0 ) + { + free( buf ); + return( POLARSSL_ERR_PEM_INVALID_DATA + ret ); + } + + if( enc != 0 ) + { +#if defined(POLARSSL_MD5_C) && (defined(POLARSSL_DES_C) || defined(POLARSSL_AES_C)) + if( pwd == NULL ) + { + free( buf ); + return( POLARSSL_ERR_PEM_PASSWORD_REQUIRED ); + } + +#if defined(POLARSSL_DES_C) + if( enc_alg == POLARSSL_CIPHER_DES_EDE3_CBC ) + pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen ); + else if( enc_alg == POLARSSL_CIPHER_DES_CBC ) + pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen ); +#endif /* POLARSSL_DES_C */ + +#if defined(POLARSSL_AES_C) + if( enc_alg == POLARSSL_CIPHER_AES_128_CBC ) + pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen ); + else if( enc_alg == POLARSSL_CIPHER_AES_192_CBC ) + pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen ); + else if( enc_alg == POLARSSL_CIPHER_AES_256_CBC ) + pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen ); +#endif /* POLARSSL_AES_C */ + + if( buf[0] != 0x30 || buf[1] != 0x82 || + buf[4] != 0x02 || buf[5] != 0x01 ) + { + free( buf ); + return( POLARSSL_ERR_PEM_PASSWORD_MISMATCH ); + } +#else + free( buf ); + return( POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE ); +#endif + } + + ctx->buf = buf; + ctx->buflen = len; + + return( 0 ); +} + +void pem_free( pem_context *ctx ) +{ + if( ctx->buf ) + free( ctx->buf ); + + if( ctx->info ) + free( ctx->info ); + + memset( ctx, 0, sizeof( pem_context ) ); +} + +#endif diff --git a/src/libpolarssl/pem.h b/src/libpolarssl/pem.h new file mode 100644 index 0000000..e95dc10 --- /dev/null +++ b/src/libpolarssl/pem.h @@ -0,0 +1,105 @@ +/** + * \file pem.h + * + * \brief Privacy Enhanced Mail (PEM) decoding + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_PEM_H +#define POLARSSL_PEM_H + +#include + +/** + * \name PEM Error codes + * These error codes are returned in case of errors reading the + * PEM data. + * \{ + */ +#define POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT -0x1080 /**< No PEM header or footer found. */ +#define POLARSSL_ERR_PEM_INVALID_DATA -0x1100 /**< PEM string is not as expected. */ +#define POLARSSL_ERR_PEM_MALLOC_FAILED -0x1180 /**< Failed to allocate memory. */ +#define POLARSSL_ERR_PEM_INVALID_ENC_IV -0x1200 /**< RSA IV is not in hex-format. */ +#define POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG -0x1280 /**< Unsupported key encryption algorithm. */ +#define POLARSSL_ERR_PEM_PASSWORD_REQUIRED -0x1300 /**< Private key password can't be empty. */ +#define POLARSSL_ERR_PEM_PASSWORD_MISMATCH -0x1380 /**< Given private key password does not allow for correct decryption. */ +#define POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE -0x1400 /**< Unavailable feature, e.g. hashing/encryption combination. */ +#define POLARSSL_ERR_PEM_BAD_INPUT_DATA -0x1480 /**< Bad input parameters to function. */ +/* \} name */ + +/** + * \brief PEM context structure + */ +typedef struct +{ + unsigned char *buf; /*!< buffer for decoded data */ + size_t buflen; /*!< length of the buffer */ + unsigned char *info; /*!< buffer for extra header information */ +} +pem_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PEM context setup + * + * \param ctx context to be initialized + */ +void pem_init( pem_context *ctx ); + +/** + * \brief Read a buffer for PEM information and store the resulting + * data into the specified context buffers. + * + * \param ctx context to use + * \param header header string to seek and expect + * \param footer footer string to seek and expect + * \param data source data to look in + * \param pwd password for decryption (can be NULL) + * \param pwdlen length of password + * \param use_len destination for total length used (set after header is + * correctly read, so unless you get + * POLARSSL_ERR_PEM_BAD_INPUT_DATA or + * POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT, use_len is + * the length to skip) + * + * \return 0 on success, ior a specific PEM error code + */ +int pem_read_buffer( pem_context *ctx, char *header, char *footer, + const unsigned char *data, + const unsigned char *pwd, + size_t pwdlen, size_t *use_len ); + +/** + * \brief PEM context memory freeing + * + * \param ctx context to be freed + */ +void pem_free( pem_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* pem.h */ diff --git a/src/libpolarssl/pkcs11.c b/src/libpolarssl/pkcs11.c new file mode 100644 index 0000000..41eb0f4 --- /dev/null +++ b/src/libpolarssl/pkcs11.c @@ -0,0 +1,238 @@ +/** + * \file pkcs11.c + * + * \brief Wrapper for PKCS#11 library libpkcs11-helper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "pkcs11.h" + +#if defined(POLARSSL_PKCS11_C) + +#include + +int pkcs11_x509_cert_init( x509_cert *cert, pkcs11h_certificate_t pkcs11_cert ) +{ + int ret = 1; + unsigned char *cert_blob = NULL; + size_t cert_blob_size = 0; + + if( cert == NULL ) + { + ret = 2; + goto cleanup; + } + + if( pkcs11h_certificate_getCertificateBlob( pkcs11_cert, NULL, &cert_blob_size ) != CKR_OK ) + { + ret = 3; + goto cleanup; + } + + cert_blob = malloc( cert_blob_size ); + if( NULL == cert_blob ) + { + ret = 4; + goto cleanup; + } + + if( pkcs11h_certificate_getCertificateBlob( pkcs11_cert, cert_blob, &cert_blob_size ) != CKR_OK ) + { + ret = 5; + goto cleanup; + } + + if( 0 != x509parse_crt(cert, cert_blob, cert_blob_size ) ) + { + ret = 6; + goto cleanup; + } + + ret = 0; + +cleanup: + if( NULL != cert_blob ) + free( cert_blob ); + + return ret; +} + + +int pkcs11_priv_key_init( pkcs11_context *priv_key, + pkcs11h_certificate_t pkcs11_cert ) +{ + int ret = 1; + x509_cert cert; + + memset( &cert, 0, sizeof( cert ) ); + + if( priv_key == NULL ) + goto cleanup; + + if( 0 != pkcs11_x509_cert_init( &cert, pkcs11_cert ) ) + goto cleanup; + + priv_key->len = cert.rsa.len; + priv_key->pkcs11h_cert = pkcs11_cert; + + ret = 0; + +cleanup: + x509_free( &cert ); + + return ret; +} + +void pkcs11_priv_key_free( pkcs11_context *priv_key ) +{ + if( NULL != priv_key ) + pkcs11h_certificate_freeCertificate( priv_key->pkcs11h_cert ); +} + +int pkcs11_decrypt( pkcs11_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ) +{ + size_t input_len, output_len; + + if( NULL == ctx ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + if( RSA_PUBLIC == mode ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + output_len = input_len = ctx->len; + + if( input_len < 16 || input_len > output_max_len ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + /* Determine size of output buffer */ + if( pkcs11h_certificate_decryptAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, input, + input_len, NULL, &output_len ) != CKR_OK ) + { + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + if( output_len > output_max_len ) + return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE ); + + if( pkcs11h_certificate_decryptAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, input, + input_len, output, &output_len ) != CKR_OK ) + { + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + *olen = output_len; + return( 0 ); +} + +int pkcs11_sign( pkcs11_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t olen, asn_len; + unsigned char *p = sig; + + if( NULL == ctx ) + return POLARSSL_ERR_RSA_BAD_INPUT_DATA; + + if( RSA_PUBLIC == mode ) + return POLARSSL_ERR_RSA_BAD_INPUT_DATA; + + olen = ctx->len; + + switch( hash_id ) + { + case SIG_RSA_RAW: + asn_len = 0; + memcpy( p, hash, hashlen ); + break; + + case SIG_RSA_MD2: + asn_len = OID_SIZE(ASN1_HASH_MDX); + memcpy( p, ASN1_HASH_MDX, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[13] = 2; break; + + case SIG_RSA_MD4: + asn_len = OID_SIZE(ASN1_HASH_MDX); + memcpy( p, ASN1_HASH_MDX, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[13] = 4; break; + + case SIG_RSA_MD5: + asn_len = OID_SIZE(ASN1_HASH_MDX); + memcpy( p, ASN1_HASH_MDX, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[13] = 5; break; + + case SIG_RSA_SHA1: + asn_len = OID_SIZE(ASN1_HASH_SHA1); + memcpy( p, ASN1_HASH_SHA1, asn_len ); + memcpy( p + 15, hash, hashlen ); + break; + + case SIG_RSA_SHA224: + asn_len = OID_SIZE(ASN1_HASH_SHA2X); + memcpy( p, ASN1_HASH_SHA2X, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[1] += hashlen; p[14] = 4; p[18] += hashlen; break; + + case SIG_RSA_SHA256: + asn_len = OID_SIZE(ASN1_HASH_SHA2X); + memcpy( p, ASN1_HASH_SHA2X, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[1] += hashlen; p[14] = 1; p[18] += hashlen; break; + + case SIG_RSA_SHA384: + asn_len = OID_SIZE(ASN1_HASH_SHA2X); + memcpy( p, ASN1_HASH_SHA2X, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[1] += hashlen; p[14] = 2; p[18] += hashlen; break; + + case SIG_RSA_SHA512: + asn_len = OID_SIZE(ASN1_HASH_SHA2X); + memcpy( p, ASN1_HASH_SHA2X, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[1] += hashlen; p[14] = 3; p[18] += hashlen; break; + + default: + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + if( pkcs11h_certificate_signAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, sig, + asn_len + hashlen, sig, &olen ) != CKR_OK ) + { + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + return( 0 ); +} + +#endif /* defined(POLARSSL_PKCS11_C) */ diff --git a/src/libpolarssl/pkcs11.h b/src/libpolarssl/pkcs11.h new file mode 100644 index 0000000..003d3f5 --- /dev/null +++ b/src/libpolarssl/pkcs11.h @@ -0,0 +1,161 @@ +/** + * \file pkcs11.h + * + * \brief Wrapper for PKCS#11 library libpkcs11-helper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_PKCS11_H +#define POLARSSL_PKCS11_H + +#include "config.h" + +#if defined(POLARSSL_PKCS11_C) + +#include "x509.h" + +#include + +#if defined(_MSC_VER) && !defined(inline) +#define inline _inline +#else +#if defined(__ARMCC_VERSION) && !defined(inline) +#define inline __inline +#endif /* __ARMCC_VERSION */ +#endif /*_MSC_VER */ + +/** + * Context for PKCS #11 private keys. + */ +typedef struct { + pkcs11h_certificate_t pkcs11h_cert; + int len; +} pkcs11_context; + +/** + * Fill in a PolarSSL certificate, based on the given PKCS11 helper certificate. + * + * \param cert X.509 certificate to fill + * \param pkcs11h_cert PKCS #11 helper certificate + * + * \return 0 on success. + */ +int pkcs11_x509_cert_init( x509_cert *cert, pkcs11h_certificate_t pkcs11h_cert ); + +/** + * Initialise a pkcs11_context, storing the given certificate. Note that the + * pkcs11_context will take over control of the certificate, freeing it when + * done. + * + * \param priv_key Private key structure to fill. + * \param pkcs11_cert PKCS #11 helper certificate + * + * \return 0 on success + */ +int pkcs11_priv_key_init( pkcs11_context *priv_key, + pkcs11h_certificate_t pkcs11_cert ); + +/** + * Free the contents of the given private key context. Note that the structure + * itself is not freed. + * + * \param priv_key Private key structure to cleanup + */ +void pkcs11_priv_key_free( pkcs11_context *priv_key ); + +/** + * \brief Do an RSA private key decrypt, then remove the message padding + * + * \param ctx PKCS #11 context + * \param mode must be RSA_PRIVATE, for compatibility with rsa.c's signature + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param olen will contain the plaintext length + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int pkcs11_decrypt( pkcs11_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Do a private RSA to sign a message digest + * + * \param ctx PKCS #11 context + * \param mode must be RSA_PRIVATE, for compatibility with rsa.c's signature + * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} + * \param hashlen message digest length (for SIG_RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an POLARSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int pkcs11_sign( pkcs11_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * SSL/TLS wrappers for PKCS#11 functions + */ +static inline int ssl_pkcs11_decrypt( void *ctx, int mode, size_t *olen, + const unsigned char *input, unsigned char *output, + size_t output_max_len ) +{ + return pkcs11_decrypt( (pkcs11_context *) ctx, mode, olen, input, output, + output_max_len ); +} + +static inline int ssl_pkcs11_sign( void *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + int mode, int hash_id, unsigned int hashlen, + const unsigned char *hash, unsigned char *sig ) +{ + ((void) f_rng); + ((void) p_rng); + return pkcs11_sign( (pkcs11_context *) ctx, mode, hash_id, + hashlen, hash, sig ); +} + +static inline size_t ssl_pkcs11_key_len( void *ctx ) +{ + return ( (pkcs11_context *) ctx )->len; +} + +#endif /* POLARSSL_PKCS11_C */ + +#endif /* POLARSSL_PKCS11_H */ diff --git a/src/libpolarssl/pkcs12.c b/src/libpolarssl/pkcs12.c new file mode 100644 index 0000000..59d8551 --- /dev/null +++ b/src/libpolarssl/pkcs12.c @@ -0,0 +1,330 @@ +/* + * PKCS#12 Personal Information Exchange Syntax + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The PKCS #12 Personal Information Exchange Syntax Standard v1.1 + * + * http://www.rsa.com/rsalabs/pkcs/files/h11301-wp-pkcs-12v1-1-personal-information-exchange-syntax.pdf + * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1-1.asn + */ + +#include "config.h" + +#if defined(POLARSSL_PKCS12_C) + +#include "pkcs12.h" +#include "asn1.h" +#include "cipher.h" + +#if defined(POLARSSL_ARC4_C) +#include "arc4.h" +#endif + +#if defined(POLARSSL_DES_C) +#include "des.h" +#endif + +static int pkcs12_parse_pbe_params( unsigned char **p, + const unsigned char *end, + asn1_buf *salt, int *iterations ) +{ + int ret; + size_t len = 0; + + /* + * pkcs-12PbeParams ::= SEQUENCE { + * salt OCTET STRING, + * iterations INTEGER + * } + * + */ + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + return( POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); + } + + end = *p + len; + + if( ( ret = asn1_get_tag( p, end, &salt->len, ASN1_OCTET_STRING ) ) != 0 ) + return( POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); + + salt->p = *p; + *p += salt->len; + + if( ( ret = asn1_get_int( p, end, iterations ) ) != 0 ) + return( POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); + + if( *p != end ) + return( POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +static int pkcs12_pbe_derive_key_iv( asn1_buf *pbe_params, md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + unsigned char *key, size_t keylen, + unsigned char *iv, size_t ivlen ) +{ + int ret, iterations; + asn1_buf salt; + size_t i; + unsigned char *p, *end; + unsigned char unipwd[258]; + + memset(&salt, 0, sizeof(asn1_buf)); + memset(&unipwd, 0, sizeof(unipwd)); + + p = pbe_params->p; + end = p + pbe_params->len; + + if( ( ret = pkcs12_parse_pbe_params( &p, end, &salt, &iterations ) ) != 0 ) + return( ret ); + + for(i = 0; i < pwdlen; i++) + unipwd[i * 2 + 1] = pwd[i]; + + if( ( ret = pkcs12_derivation( key, keylen, unipwd, pwdlen * 2 + 2, + salt.p, salt.len, md_type, + PKCS12_DERIVE_KEY, iterations ) ) != 0 ) + { + return( ret ); + } + + if( iv == NULL || ivlen == 0 ) + return( 0 ); + + if( ( ret = pkcs12_derivation( iv, ivlen, unipwd, pwdlen * 2 + 2, + salt.p, salt.len, md_type, + PKCS12_DERIVE_IV, iterations ) ) != 0 ) + { + return( ret ); + } + return( 0 ); +} + +int pkcs12_pbe_sha1_rc4_128( asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t len, + unsigned char *output ) +{ +#if !defined(POLARSSL_ARC4_C) + ((void) pbe_params); + ((void) mode); + ((void) pwd); + ((void) pwdlen); + ((void) data); + ((void) len); + ((void) output); + return( POLARSSL_ERR_PKCS12_FEATURE_UNAVAILABLE ); +#else + int ret; + unsigned char key[16]; + arc4_context ctx; + ((void) mode); + + if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, POLARSSL_MD_SHA1, + pwd, pwdlen, + key, 16, NULL, 0 ) ) != 0 ) + { + return( ret ); + } + + arc4_setup( &ctx, key, 16 ); + if( ( ret = arc4_crypt( &ctx, len, data, output ) ) != 0 ) + return( ret ); + + return( 0 ); +#endif /* POLARSSL_ARC4_C */ +} + +int pkcs12_pbe( asn1_buf *pbe_params, int mode, + cipher_type_t cipher_type, md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t len, + unsigned char *output ) +{ + int ret, keylen = 0; + unsigned char key[32]; + unsigned char iv[16]; + const cipher_info_t *cipher_info; + cipher_context_t cipher_ctx; + size_t olen = 0; + + cipher_info = cipher_info_from_type( cipher_type ); + if( cipher_info == NULL ) + return( POLARSSL_ERR_PKCS12_FEATURE_UNAVAILABLE ); + + keylen = cipher_info->key_length / 8; + + if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, md_type, pwd, pwdlen, + key, keylen, + iv, cipher_info->iv_size ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cipher_init_ctx( &cipher_ctx, cipher_info ) ) != 0 ) + return( ret ); + + if( ( ret = cipher_setkey( &cipher_ctx, key, keylen, mode ) ) != 0 ) + return( ret ); + + if( ( ret = cipher_reset( &cipher_ctx, iv ) ) != 0 ) + return( ret ); + + if( ( ret = cipher_update( &cipher_ctx, data, len, + output, &olen ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 ) + return( POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH ); + + return( 0 ); +} + +static void pkcs12_fill_buffer( unsigned char *data, size_t data_len, + const unsigned char *filler, size_t fill_len ) +{ + unsigned char *p = data; + size_t use_len; + + while( data_len > 0 ) + { + use_len = ( data_len > fill_len ) ? fill_len : data_len; + memcpy( p, filler, use_len ); + p += use_len; + data_len -= use_len; + } +} + +int pkcs12_derivation( unsigned char *data, size_t datalen, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *salt, size_t saltlen, + md_type_t md_type, int id, int iterations ) +{ + int ret, i; + unsigned int j; + + unsigned char diversifier[128]; + unsigned char salt_block[128], pwd_block[128], hash_block[128]; + unsigned char hash_output[POLARSSL_MD_MAX_SIZE]; + unsigned char *p; + unsigned char c; + + size_t hlen, use_len, v; + + const md_info_t *md_info; + md_context_t md_ctx; + + // This version only allows max of 64 bytes of password or salt + if( datalen > 128 || pwdlen > 64 || saltlen > 64 ) + return( POLARSSL_ERR_PKCS12_BAD_INPUT_DATA ); + + md_info = md_info_from_type( md_type ); + if( md_info == NULL ) + return( POLARSSL_ERR_PKCS12_FEATURE_UNAVAILABLE ); + + if ( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 ) + return( ret ); + hlen = md_get_size( md_info ); + + if( hlen <= 32 ) + v = 64; + else + v = 128; + + memset( diversifier, (unsigned char) id, v ); + + pkcs12_fill_buffer( salt_block, v, salt, saltlen ); + pkcs12_fill_buffer( pwd_block, v, pwd, pwdlen ); + + p = data; + while( datalen > 0 ) + { + // Calculate hash( diversifier || salt_block || pwd_block ) + if( ( ret = md_starts( &md_ctx ) ) != 0 ) + return( ret ); + + if( ( ret = md_update( &md_ctx, diversifier, v ) ) != 0 ) + return( ret ); + + if( ( ret = md_update( &md_ctx, salt_block, v ) ) != 0 ) + return( ret ); + + if( ( ret = md_update( &md_ctx, pwd_block, v ) ) != 0 ) + return( ret ); + + if( ( ret = md_finish( &md_ctx, hash_output ) ) != 0 ) + return( ret ); + + // Perform remaining ( iterations - 1 ) recursive hash calculations + for( i = 1; i < iterations; i++ ) + { + if( ( ret = md( md_info, hash_output, hlen, hash_output ) ) != 0 ) + return( ret ); + } + + use_len = ( datalen > hlen ) ? hlen : datalen; + memcpy( p, hash_output, use_len ); + datalen -= use_len; + p += use_len; + + if( datalen == 0 ) + break; + + // Concatenating copies of hash_output into hash_block (B) + pkcs12_fill_buffer( hash_block, v, hash_output, hlen ); + + // B += 1 + for( i = v; i > 0; i-- ) + if( ++hash_block[i - 1] != 0 ) + break; + + // salt_block += B + c = 0; + for( i = v; i > 0; i-- ) + { + j = salt_block[i - 1] + hash_block[i - 1] + c; + c = (unsigned char) (j >> 8); + salt_block[i - 1] = j & 0xFF; + } + + // pwd_block += B + c = 0; + for( i = v; i > 0; i-- ) + { + j = pwd_block[i - 1] + hash_block[i - 1] + c; + c = (unsigned char) (j >> 8); + pwd_block[i - 1] = j & 0xFF; + } + } + + return( 0 ); +} + +#endif /* POLARSSL_PKCS12_C */ diff --git a/src/libpolarssl/pkcs12.h b/src/libpolarssl/pkcs12.h new file mode 100644 index 0000000..9a45771 --- /dev/null +++ b/src/libpolarssl/pkcs12.h @@ -0,0 +1,131 @@ +/** + * \file pkcs12.h + * + * \brief PKCS#12 Personal Information Exchange Syntax + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_PKCS12_H +#define POLARSSL_PKCS12_H + +#include + +#include "md.h" +#include "cipher.h" +#include "asn1.h" + +#define POLARSSL_ERR_PKCS12_BAD_INPUT_DATA -0x1F80 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_PKCS12_FEATURE_UNAVAILABLE -0x1F00 /**< Feature not available, e.g. unsupported encryption scheme. */ +#define POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT -0x1E80 /**< PBE ASN.1 data not as expected. */ +#define POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH -0x1E00 /**< Given private key password does not allow for correct decryption. */ + +#define PKCS12_DERIVE_KEY 1 /*< encryption/decryption key */ +#define PKCS12_DERIVE_IV 2 /*< initialization vector */ +#define PKCS12_DERIVE_MAC_KEY 3 /*< integrity / MAC key */ + +#define PKCS12_PBE_DECRYPT 0 +#define PKCS12_PBE_ENCRYPT 1 + +/* + * PKCS#12 PBE types + */ +#define OID_PKCS12 "\x2a\x86\x48\x86\xf7\x0d\x01\x0c" +#define OID_PKCS12_PBE_SHA1_RC4_128 OID_PKCS12 "\x01\x01" +#define OID_PKCS12_PBE_SHA1_DES3_EDE_CBC OID_PKCS12 "\x01\x03" +#define OID_PKCS12_PBE_SHA1_DES2_EDE_CBC OID_PKCS12 "\x01\x04" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PKCS12 Password Based function (encryption / decryption) + * for pbeWithSHAAnd128BitRC4 + * + * \param pbe_params an ASN1 buffer containing the pkcs-12PbeParams structure + * \param mode either PKCS12_PBE_ENCRYPT or PKCS12_PBE_DECRYPT + * \param pwd the password used (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param input the input data + * \param len data length + * \param output the output buffer + * + * \return 0 if successful, or a PolarSSL error code + */ +int pkcs12_pbe_sha1_rc4_128( asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *input, size_t len, + unsigned char *output ); + +/** + * \brief PKCS12 Password Based function (encryption / decryption) + * for cipher-based and md-based PBE's + * + * \param pbe_params an ASN1 buffer containing the pkcs-12PbeParams structure + * \param mode either PKCS12_PBE_ENCRYPT or PKCS12_PBE_DECRYPT + * \param cipher_type the cipher used + * \param md_type the md used + * \param pwd the password used (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param input the input data + * \param len data length + * \param output the output buffer + * + * \return 0 if successful, or a PolarSSL error code + */ +int pkcs12_pbe( asn1_buf *pbe_params, int mode, + cipher_type_t cipher_type, md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *input, size_t len, + unsigned char *output ); + +/** + * \brief The PKCS#12 derivation function uses a password and a salt + * to produce pseudo-random bits for a particular "purpose". + * + * Depending on the given id, this function can produce an + * encryption/decryption key, an nitialization vector or an + * integrity key. + * + * \param data buffer to store the derived data in + * \param datalen length to fill + * \param pwd password to use (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param salt salt buffer to use + * \param saltlen length of the salt + * \param md md type to use during the derivation + * \param id id that describes the purpose (can be PKCS12_DERIVE_KEY, + * PKCS12_DERIVE_IV or PKCS12_DERIVE_MAC_KEY) + * \param iterations number of iterations + * + * \return 0 if successful, or a MD, BIGNUM type error. + */ +int pkcs12_derivation( unsigned char *data, size_t datalen, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *salt, size_t saltlen, + md_type_t md, int id, int iterations ); + +#ifdef __cplusplus +} +#endif + +#endif /* pkcs12.h */ diff --git a/src/libpolarssl/pkcs5.c b/src/libpolarssl/pkcs5.c new file mode 100644 index 0000000..514c3f3 --- /dev/null +++ b/src/libpolarssl/pkcs5.c @@ -0,0 +1,415 @@ +/** + * \file pkcs5.c + * + * \brief PKCS#5 functions + * + * \author Mathias Olsson + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * PKCS#5 includes PBKDF2 and more + * + * http://tools.ietf.org/html/rfc2898 (Specification) + * http://tools.ietf.org/html/rfc6070 (Test vectors) + */ + +#include "config.h" + +#if defined(POLARSSL_PKCS5_C) + +#include "pkcs5.h" +#include "asn1.h" +#include "cipher.h" + +#define OID_CMP(oid_str, oid_buf) \ + ( ( OID_SIZE(oid_str) == (oid_buf)->len ) && \ + memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) == 0) + +static int pkcs5_parse_pbkdf2_params( unsigned char **p, + const unsigned char *end, + asn1_buf *salt, int *iterations, + int *keylen, md_type_t *md_type ) +{ + int ret; + size_t len = 0; + asn1_buf prf_alg_oid; + + /* + * PBKDF2-params ::= SEQUENCE { + * salt OCTET STRING, + * iterationCount INTEGER, + * keyLength INTEGER OPTIONAL + * prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1 + * } + * + */ + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + end = *p + len; + + if( ( ret = asn1_get_tag( p, end, &salt->len, ASN1_OCTET_STRING ) ) != 0 ) + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); + + salt->p = *p; + *p += salt->len; + + if( ( ret = asn1_get_int( p, end, iterations ) ) != 0 ) + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); + + if( *p == end ) + return( 0 ); + + if( ( ret = asn1_get_int( p, end, keylen ) ) != 0 ) + { + if( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + if( *p == end ) + return( 0 ); + + if( ( ret = asn1_get_tag( p, end, &prf_alg_oid.len, ASN1_OID ) ) != 0 ) + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); + + if( !OID_CMP( OID_HMAC_SHA1, &prf_alg_oid ) ) + return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + *md_type = POLARSSL_MD_SHA1; + + if( *p != end ) + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int pkcs5_pbes2( asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t datalen, + unsigned char *output ) +{ + int ret, iterations = 0, keylen = 0; + unsigned char *p, *end, *end2; + asn1_buf kdf_alg_oid, enc_scheme_oid, salt; + md_type_t md_type = POLARSSL_MD_SHA1; + unsigned char key[32], iv[32]; + size_t len = 0, olen = 0; + const md_info_t *md_info; + const cipher_info_t *cipher_info; + md_context_t md_ctx; + cipher_context_t cipher_ctx; + + p = pbe_params->p; + end = p + pbe_params->len; + + /* + * PBES2-params ::= SEQUENCE { + * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, + * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} + * } + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + end2 = p + len; + + if( ( ret = asn1_get_tag( &p, end2, &kdf_alg_oid.len, ASN1_OID ) ) != 0 ) + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); + + kdf_alg_oid.p = p; + p += kdf_alg_oid.len; + + // Only PBKDF2 supported at the moment + // + if( !OID_CMP( OID_PKCS5_PBKDF2, &kdf_alg_oid ) ) + return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( ( ret = pkcs5_parse_pbkdf2_params( &p, end2, + &salt, &iterations, &keylen, + &md_type ) ) != 0 ) + { + return( ret ); + } + + md_info = md_info_from_type( md_type ); + if( md_info == NULL ) + return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + end2 = p + len; + + if( ( ret = asn1_get_tag( &p, end2, &enc_scheme_oid.len, ASN1_OID ) ) != 0 ) + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); + + enc_scheme_oid.p = p; + p += enc_scheme_oid.len; + +#if defined(POLARSSL_DES_C) + // Only DES-CBC and DES-EDE3-CBC supported at the moment + // + if( OID_CMP( OID_DES_EDE3_CBC, &enc_scheme_oid ) ) + { + cipher_info = cipher_info_from_type( POLARSSL_CIPHER_DES_EDE3_CBC ); + } + else if( OID_CMP( OID_DES_CBC, &enc_scheme_oid ) ) + { + cipher_info = cipher_info_from_type( POLARSSL_CIPHER_DES_CBC ); + } + else +#endif /* POLARSSL_DES_C */ + return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( cipher_info == NULL ) + return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + keylen = cipher_info->key_length / 8; + + if( ( ret = asn1_get_tag( &p, end2, &len, ASN1_OCTET_STRING ) ) != 0 ) + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret ); + + if( len != cipher_info->iv_size ) + return( POLARSSL_ERR_PKCS5_INVALID_FORMAT ); + + memcpy( iv, p, len ); + + if( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 ) + return( ret ); + + if( ( ret = cipher_init_ctx( &cipher_ctx, cipher_info ) ) != 0 ) + return( ret ); + + if ( ( ret = pkcs5_pbkdf2_hmac( &md_ctx, pwd, pwdlen, salt.p, salt.len, + iterations, keylen, key ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cipher_setkey( &cipher_ctx, key, keylen, mode ) ) != 0 ) + return( ret ); + + if( ( ret = cipher_reset( &cipher_ctx, iv ) ) != 0 ) + return( ret ); + + if( ( ret = cipher_update( &cipher_ctx, data, datalen, + output, &olen ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 ) + return( POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH ); + + return( 0 ); +} + +int pkcs5_pbkdf2_hmac( md_context_t *ctx, const unsigned char *password, + size_t plen, const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output ) +{ + int ret, j; + unsigned int i; + unsigned char md1[POLARSSL_MD_MAX_SIZE]; + unsigned char work[POLARSSL_MD_MAX_SIZE]; + unsigned char md_size = md_get_size( ctx->md_info ); + size_t use_len; + unsigned char *out_p = output; + unsigned char counter[4]; + + memset( counter, 0, 4 ); + counter[3] = 1; + + if( iteration_count > 0xFFFFFFFF ) + return( POLARSSL_ERR_PKCS5_BAD_INPUT_DATA ); + + while( key_length ) + { + // U1 ends up in work + // + if( ( ret = md_hmac_starts( ctx, password, plen ) ) != 0 ) + return( ret ); + + if( ( ret = md_hmac_update( ctx, salt, slen ) ) != 0 ) + return( ret ); + + if( ( ret = md_hmac_update( ctx, counter, 4 ) ) != 0 ) + return( ret ); + + if( ( ret = md_hmac_finish( ctx, work ) ) != 0 ) + return( ret ); + + memcpy( md1, work, md_size ); + + for ( i = 1; i < iteration_count; i++ ) + { + // U2 ends up in md1 + // + if( ( ret = md_hmac_starts( ctx, password, plen ) ) != 0 ) + return( ret ); + + if( ( ret = md_hmac_update( ctx, md1, md_size ) ) != 0 ) + return( ret ); + + if( ( ret = md_hmac_finish( ctx, md1 ) ) != 0 ) + return( ret ); + + // U1 xor U2 + // + for( j = 0; j < md_size; j++ ) + work[j] ^= md1[j]; + } + + use_len = ( key_length < md_size ) ? key_length : md_size; + memcpy( out_p, work, use_len ); + + key_length -= use_len; + out_p += use_len; + + for( i = 4; i > 0; i-- ) + if( ++counter[i - 1] != 0 ) + break; + } + + return( 0 ); +} + +#if defined(POLARSSL_SELF_TEST) + +#include + +#define MAX_TESTS 6 + +size_t plen[MAX_TESTS] = + { 8, 8, 8, 8, 24, 9 }; + +unsigned char password[MAX_TESTS][32] = +{ + "password", + "password", + "password", + "password", + "passwordPASSWORDpassword", + "pass\0word", +}; + +size_t slen[MAX_TESTS] = + { 4, 4, 4, 4, 36, 5 }; + +unsigned char salt[MAX_TESTS][40] = +{ + "salt", + "salt", + "salt", + "salt", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + "sa\0lt", +}; + +uint32_t it_cnt[MAX_TESTS] = + { 1, 2, 4096, 16777216, 4096, 4096 }; + +uint32_t key_len[MAX_TESTS] = + { 20, 20, 20, 20, 25, 16 }; + + +unsigned char result_key[MAX_TESTS][32] = +{ + { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, + 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, + 0x2f, 0xe0, 0x37, 0xa6 }, + { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, + 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, + 0xd8, 0xde, 0x89, 0x57 }, + { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, + 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, + 0x65, 0xa4, 0x29, 0xc1 }, + { 0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4, + 0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c, + 0x26, 0x34, 0xe9, 0x84 }, + { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, + 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a, + 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, + 0x38 }, + { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d, + 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 }, +}; + +int pkcs5_self_test( int verbose ) +{ + md_context_t sha1_ctx; + const md_info_t *info_sha1; + int ret, i; + unsigned char key[64]; + + info_sha1 = md_info_from_type( POLARSSL_MD_SHA1 ); + if( info_sha1 == NULL ) + return( 1 ); + + if( ( ret = md_init_ctx( &sha1_ctx, info_sha1 ) ) != 0 ) + return( 1 ); + + for( i = 0; i < MAX_TESTS; i++ ) + { + printf( " PBKDF2 (SHA1) #%d: ", i ); + + ret = pkcs5_pbkdf2_hmac( &sha1_ctx, password[i], plen[i], salt[i], + slen[i], it_cnt[i], key_len[i], key ); + if( ret != 0 || + memcmp( result_key[i], key, key_len[i] ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + printf( "\n" ); + + return( 0 ); +} + +#endif /* POLARSSL_SELF_TEST */ + +#endif /* POLARSSL_PKCS5_C */ diff --git a/src/libpolarssl/pkcs5.h b/src/libpolarssl/pkcs5.h new file mode 100644 index 0000000..b8c742e --- /dev/null +++ b/src/libpolarssl/pkcs5.h @@ -0,0 +1,122 @@ +/** + * \file pkcs#5.h + * + * \brief PKCS#5 functions + * + * \author Mathias Olsson + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_PKCS5_H +#define POLARSSL_PKCS5_H + +#include + +#include "asn1.h" +#include "md.h" + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define POLARSSL_ERR_PKCS5_BAD_INPUT_DATA -0x3f80 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_PKCS5_INVALID_FORMAT -0x3f00 /**< Unexpected ASN.1 data. */ +#define POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE -0x3e80 /**< Requested encryption or digest alg not available. */ +#define POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH -0x3e00 /**< Given private key password does not allow for correct decryption. */ + +#define PKCS5_DECRYPT 0 +#define PKCS5_ENCRYPT 1 + +/* + * PKCS#5 OIDs + */ +#define OID_PKCS5 "\x2a\x86\x48\x86\xf7\x0d\x01\x05" +#define OID_PKCS5_PBES2 OID_PKCS5 "\x0d" +#define OID_PKCS5_PBKDF2 OID_PKCS5 "\x0c" + +/* + * Encryption Algorithm OIDs + */ +#define OID_DES_CBC "\x2b\x0e\x03\x02\x07" +#define OID_DES_EDE3_CBC "\x2a\x86\x48\x86\xf7\x0d\x03\x07" + +/* + * Digest Algorithm OIDs + */ +#define OID_HMAC_SHA1 "\x2a\x86\x48\x86\xf7\x0d\x02\x07" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PKCS#5 PBES2 function + * + * \param pbe_params the ASN.1 algorithm parameters + * \param mode either PKCS5_DECRYPT or PKCS5_ENCRYPT + * \param pwd password to use when generating key + * \param plen length of password + * \param data data to process + * \param datalen length of data + * \param output output buffer + * + * \returns 0 on success, or a PolarSSL error code if verification fails. + */ +int pkcs5_pbes2( asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t datalen, + unsigned char *output ); + +/** + * \brief PKCS#5 PBKDF2 using HMAC + * + * \param ctx Generic HMAC context + * \param password Password to use when generating key + * \param plen Length of password + * \param salt Salt to use when generating key + * \param slen Length of salt + * \param iteration_count Iteration count + * \param key_length Length of generated key + * \param output Generated key. Must be at least as big as key_length + * + * \returns 0 on success, or a PolarSSL error code if verification fails. + */ +int pkcs5_pbkdf2_hmac( md_context_t *ctx, const unsigned char *password, + size_t plen, const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int pkcs5_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* pkcs5.h */ diff --git a/src/libpolarssl/rsa.c b/src/libpolarssl/rsa.c new file mode 100644 index 0000000..0e2fd6e --- /dev/null +++ b/src/libpolarssl/rsa.c @@ -0,0 +1,1466 @@ +/* + * The RSA public-key cryptosystem + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * RSA was designed by Ron Rivest, Adi Shamir and Len Adleman. + * + * http://theory.lcs.mit.edu/~rivest/rsapaper.pdf + * http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf + */ + +#include "config.h" + +#if defined(POLARSSL_RSA_C) + +#include "rsa.h" + +#if defined(POLARSSL_PKCS1_V21) +#include "md.h" +#endif + +#include +#include + +/* + * Initialize an RSA context + */ +void rsa_init( rsa_context *ctx, + int padding, + int hash_id ) +{ + memset( ctx, 0, sizeof( rsa_context ) ); + + ctx->padding = padding; + ctx->hash_id = hash_id; +} + +#if defined(POLARSSL_GENPRIME) + +/* + * Generate an RSA keypair + */ +int rsa_gen_key( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ) +{ + int ret; + mpi P1, Q1, H, G; + + if( f_rng == NULL || nbits < 128 || exponent < 3 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + mpi_init( &P1 ); mpi_init( &Q1 ); mpi_init( &H ); mpi_init( &G ); + + /* + * find primes P and Q with Q < P so that: + * GCD( E, (P-1)*(Q-1) ) == 1 + */ + MPI_CHK( mpi_lset( &ctx->E, exponent ) ); + + do + { + MPI_CHK( mpi_gen_prime( &ctx->P, ( nbits + 1 ) >> 1, 0, + f_rng, p_rng ) ); + + MPI_CHK( mpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0, + f_rng, p_rng ) ); + + if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 ) + mpi_swap( &ctx->P, &ctx->Q ); + + if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 ) + continue; + + MPI_CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); + if( mpi_msb( &ctx->N ) != nbits ) + continue; + + MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) ); + MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) ); + MPI_CHK( mpi_gcd( &G, &ctx->E, &H ) ); + } + while( mpi_cmp_int( &G, 1 ) != 0 ); + + /* + * D = E^-1 mod ((P-1)*(Q-1)) + * DP = D mod (P - 1) + * DQ = D mod (Q - 1) + * QP = Q^-1 mod P + */ + MPI_CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H ) ); + MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) ); + MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) ); + MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); + + ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3; + +cleanup: + + mpi_free( &P1 ); mpi_free( &Q1 ); mpi_free( &H ); mpi_free( &G ); + + if( ret != 0 ) + { + rsa_free( ctx ); + return( POLARSSL_ERR_RSA_KEY_GEN_FAILED + ret ); + } + + return( 0 ); +} + +#endif + +/* + * Check a public RSA key + */ +int rsa_check_pubkey( const rsa_context *ctx ) +{ + if( !ctx->N.p || !ctx->E.p ) + return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); + + if( ( ctx->N.p[0] & 1 ) == 0 || + ( ctx->E.p[0] & 1 ) == 0 ) + return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); + + if( mpi_msb( &ctx->N ) < 128 || + mpi_msb( &ctx->N ) > POLARSSL_MPI_MAX_BITS ) + return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); + + if( mpi_msb( &ctx->E ) < 2 || + mpi_msb( &ctx->E ) > 64 ) + return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); + + return( 0 ); +} + +/* + * Check a private RSA key + */ +int rsa_check_privkey( const rsa_context *ctx ) +{ + int ret; + mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP; + + if( ( ret = rsa_check_pubkey( ctx ) ) != 0 ) + return( ret ); + + if( !ctx->P.p || !ctx->Q.p || !ctx->D.p ) + return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); + + mpi_init( &PQ ); mpi_init( &DE ); mpi_init( &P1 ); mpi_init( &Q1 ); + mpi_init( &H ); mpi_init( &I ); mpi_init( &G ); mpi_init( &G2 ); + mpi_init( &L1 ); mpi_init( &L2 ); mpi_init( &DP ); mpi_init( &DQ ); + mpi_init( &QP ); + + MPI_CHK( mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) ); + MPI_CHK( mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) ); + MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) ); + MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) ); + MPI_CHK( mpi_gcd( &G, &ctx->E, &H ) ); + + MPI_CHK( mpi_gcd( &G2, &P1, &Q1 ) ); + MPI_CHK( mpi_div_mpi( &L1, &L2, &H, &G2 ) ); + MPI_CHK( mpi_mod_mpi( &I, &DE, &L1 ) ); + + MPI_CHK( mpi_mod_mpi( &DP, &ctx->D, &P1 ) ); + MPI_CHK( mpi_mod_mpi( &DQ, &ctx->D, &Q1 ) ); + MPI_CHK( mpi_inv_mod( &QP, &ctx->Q, &ctx->P ) ); + /* + * Check for a valid PKCS1v2 private key + */ + if( mpi_cmp_mpi( &PQ, &ctx->N ) != 0 || + mpi_cmp_mpi( &DP, &ctx->DP ) != 0 || + mpi_cmp_mpi( &DQ, &ctx->DQ ) != 0 || + mpi_cmp_mpi( &QP, &ctx->QP ) != 0 || + mpi_cmp_int( &L2, 0 ) != 0 || + mpi_cmp_int( &I, 1 ) != 0 || + mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = POLARSSL_ERR_RSA_KEY_CHECK_FAILED; + } + +cleanup: + mpi_free( &PQ ); mpi_free( &DE ); mpi_free( &P1 ); mpi_free( &Q1 ); + mpi_free( &H ); mpi_free( &I ); mpi_free( &G ); mpi_free( &G2 ); + mpi_free( &L1 ); mpi_free( &L2 ); mpi_free( &DP ); mpi_free( &DQ ); + mpi_free( &QP ); + + if( ret == POLARSSL_ERR_RSA_KEY_CHECK_FAILED ) + return( ret ); + + if( ret != 0 ) + return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED + ret ); + + return( 0 ); +} + +/* + * Do an RSA public key operation + */ +int rsa_public( rsa_context *ctx, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t olen; + mpi T; + + mpi_init( &T ); + + MPI_CHK( mpi_read_binary( &T, input, ctx->len ) ); + + if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + mpi_free( &T ); + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + olen = ctx->len; + MPI_CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); + MPI_CHK( mpi_write_binary( &T, output, olen ) ); + +cleanup: + + mpi_free( &T ); + + if( ret != 0 ) + return( POLARSSL_ERR_RSA_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Do an RSA private key operation + */ +int rsa_private( rsa_context *ctx, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t olen; + mpi T, T1, T2; + + mpi_init( &T ); mpi_init( &T1 ); mpi_init( &T2 ); + + MPI_CHK( mpi_read_binary( &T, input, ctx->len ) ); + + if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + mpi_free( &T ); + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + +#if defined(POLARSSL_RSA_NO_CRT) + MPI_CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) ); +#else + /* + * faster decryption using the CRT + * + * T1 = input ^ dP mod P + * T2 = input ^ dQ mod Q + */ + MPI_CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) ); + MPI_CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) ); + + /* + * T = (T1 - T2) * (Q^-1 mod P) mod P + */ + MPI_CHK( mpi_sub_mpi( &T, &T1, &T2 ) ); + MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) ); + MPI_CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) ); + + /* + * output = T2 + T * Q + */ + MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) ); + MPI_CHK( mpi_add_mpi( &T, &T2, &T1 ) ); +#endif + + olen = ctx->len; + MPI_CHK( mpi_write_binary( &T, output, olen ) ); + +cleanup: + + mpi_free( &T ); mpi_free( &T1 ); mpi_free( &T2 ); + + if( ret != 0 ) + return( POLARSSL_ERR_RSA_PRIVATE_FAILED + ret ); + + return( 0 ); +} + +#if defined(POLARSSL_PKCS1_V21) +/** + * Generate and apply the MGF1 operation (from PKCS#1 v2.1) to a buffer. + * + * \param dst buffer to mask + * \param dlen length of destination buffer + * \param src source of the mask generation + * \param slen length of the source buffer + * \param md_ctx message digest context to use + */ +static void mgf_mask( unsigned char *dst, size_t dlen, unsigned char *src, size_t slen, + md_context_t *md_ctx ) +{ + unsigned char mask[POLARSSL_MD_MAX_SIZE]; + unsigned char counter[4]; + unsigned char *p; + unsigned int hlen; + size_t i, use_len; + + memset( mask, 0, POLARSSL_MD_MAX_SIZE ); + memset( counter, 0, 4 ); + + hlen = md_ctx->md_info->size; + + // Generate and apply dbMask + // + p = dst; + + while( dlen > 0 ) + { + use_len = hlen; + if( dlen < hlen ) + use_len = dlen; + + md_starts( md_ctx ); + md_update( md_ctx, src, slen ); + md_update( md_ctx, counter, 4 ); + md_finish( md_ctx, mask ); + + for( i = 0; i < use_len; ++i ) + *p++ ^= mask[i]; + + counter[3]++; + + dlen -= use_len; + } +} +#endif + +#if defined(POLARSSL_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function + */ +int rsa_rsaes_oaep_encrypt( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + size_t olen; + int ret; + unsigned char *p = output; + unsigned int hlen; + const md_info_t *md_info; + md_context_t md_ctx; + + if( ctx->padding != RSA_PKCS_V21 || f_rng == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + md_info = md_info_from_type( ctx->hash_id ); + + if( md_info == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + hlen = md_get_size( md_info ); + + if( olen < ilen + 2 * hlen + 2 || f_rng == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + memset( output, 0, olen ); + + *p++ = 0; + + // Generate a random octet string seed + // + if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 ) + return( POLARSSL_ERR_RSA_RNG_FAILED + ret ); + + p += hlen; + + // Construct DB + // + md( md_info, label, label_len, p ); + p += hlen; + p += olen - 2 * hlen - 2 - ilen; + *p++ = 1; + memcpy( p, input, ilen ); + + md_init_ctx( &md_ctx, md_info ); + + // maskedDB: Apply dbMask to DB + // + mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen, + &md_ctx ); + + // maskedSeed: Apply seedMask to seed + // + mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1, + &md_ctx ); + + md_free_ctx( &md_ctx ); + + return( ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, output, output ) + : rsa_private( ctx, output, output ) ); +} +#endif /* POLARSSL_PKCS1_V21 */ + +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function + */ +int rsa_rsaes_pkcs1_v15_encrypt( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + size_t nb_pad, olen; + int ret; + unsigned char *p = output; + + if( ctx->padding != RSA_PKCS_V15 || f_rng == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + if( olen < ilen + 11 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + nb_pad = olen - 3 - ilen; + + *p++ = 0; + if( mode == RSA_PUBLIC ) + { + *p++ = RSA_CRYPT; + + while( nb_pad-- > 0 ) + { + int rng_dl = 100; + + do { + ret = f_rng( p_rng, p, 1 ); + } while( *p == 0 && --rng_dl && ret == 0 ); + + // Check if RNG failed to generate data + // + if( rng_dl == 0 || ret != 0) + return POLARSSL_ERR_RSA_RNG_FAILED + ret; + + p++; + } + } + else + { + *p++ = RSA_SIGN; + + while( nb_pad-- > 0 ) + *p++ = 0xFF; + } + + *p++ = 0; + memcpy( p, input, ilen ); + + return( ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, output, output ) + : rsa_private( ctx, output, output ) ); +} + +/* + * Add the message padding, then do an RSA operation + */ +int rsa_pkcs1_encrypt( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + switch( ctx->padding ) + { + case RSA_PKCS_V15: + return rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen, + input, output ); + +#if defined(POLARSSL_PKCS1_V21) + case RSA_PKCS_V21: + return rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0, + ilen, input, output ); +#endif + + default: + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(POLARSSL_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function + */ +int rsa_rsaes_oaep_decrypt( rsa_context *ctx, + int mode, + const unsigned char *label, size_t label_len, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ) +{ + int ret; + size_t ilen; + unsigned char *p; + unsigned char buf[POLARSSL_MPI_MAX_SIZE]; + unsigned char lhash[POLARSSL_MD_MAX_SIZE]; + unsigned int hlen; + const md_info_t *md_info; + md_context_t md_ctx; + + if( ctx->padding != RSA_PKCS_V21 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + ilen = ctx->len; + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, input, buf ) + : rsa_private( ctx, input, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( *p++ != 0 ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + md_info = md_info_from_type( ctx->hash_id ); + if( md_info == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + hlen = md_get_size( md_info ); + + md_init_ctx( &md_ctx, md_info ); + + // Generate lHash + // + md( md_info, label, label_len, lhash ); + + // seed: Apply seedMask to maskedSeed + // + mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1, + &md_ctx ); + + // DB: Apply dbMask to maskedDB + // + mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen, + &md_ctx ); + + p += hlen; + md_free_ctx( &md_ctx ); + + // Check validity + // + if( memcmp( lhash, p, hlen ) != 0 ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + p += hlen; + + while( *p == 0 && p < buf + ilen ) + p++; + + if( p == buf + ilen ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + if( *p++ != 0x01 ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + if (ilen - (p - buf) > output_max_len) + return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE ); + + *olen = ilen - (p - buf); + memcpy( output, p, *olen ); + + return( 0 ); +} +#endif /* POLARSSL_PKCS1_V21 */ + +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function + */ +int rsa_rsaes_pkcs1_v15_decrypt( rsa_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + int ret, correct = 1; + size_t ilen, pad_count = 0; + unsigned char *p, *q; + unsigned char bt; + unsigned char buf[POLARSSL_MPI_MAX_SIZE]; + + if( ctx->padding != RSA_PKCS_V15 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + ilen = ctx->len; + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, input, buf ) + : rsa_private( ctx, input, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( *p++ != 0 ) + correct = 0; + + bt = *p++; + if( ( bt != RSA_CRYPT && mode == RSA_PRIVATE ) || + ( bt != RSA_SIGN && mode == RSA_PUBLIC ) ) + { + correct = 0; + } + + if( bt == RSA_CRYPT ) + { + while( *p != 0 && p < buf + ilen - 1 ) + pad_count += ( *p++ != 0 ); + + correct &= ( *p == 0 && p < buf + ilen - 1 ); + + q = p; + + // Also pass over all other bytes to reduce timing differences + // + while ( q < buf + ilen - 1 ) + pad_count += ( *q++ != 0 ); + + // Prevent compiler optimization of pad_count + // + correct |= pad_count & 0x100000; /* Always 0 unless 1M bit keys */ + p++; + } + else + { + while( *p == 0xFF && p < buf + ilen - 1 ) + pad_count += ( *p++ == 0xFF ); + + correct &= ( *p == 0 && p < buf + ilen - 1 ); + + q = p; + + // Also pass over all other bytes to reduce timing differences + // + while ( q < buf + ilen - 1 ) + pad_count += ( *q++ != 0 ); + + // Prevent compiler optimization of pad_count + // + correct |= pad_count & 0x100000; /* Always 0 unless 1M bit keys */ + p++; + } + + if( correct == 0 ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + if (ilen - (p - buf) > output_max_len) + return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE ); + + *olen = ilen - (p - buf); + memcpy( output, p, *olen ); + + return( 0 ); +} + +/* + * Do an RSA operation, then remove the message padding + */ +int rsa_pkcs1_decrypt( rsa_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + switch( ctx->padding ) + { + case RSA_PKCS_V15: + return rsa_rsaes_pkcs1_v15_decrypt( ctx, mode, olen, input, output, + output_max_len ); + +#if defined(POLARSSL_PKCS1_V21) + case RSA_PKCS_V21: + return rsa_rsaes_oaep_decrypt( ctx, mode, NULL, 0, olen, input, + output, output_max_len ); +#endif + + default: + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(POLARSSL_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function + */ +int rsa_rsassa_pss_sign( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t olen; + unsigned char *p = sig; + unsigned char salt[POLARSSL_MD_MAX_SIZE]; + unsigned int slen, hlen, offset = 0; + int ret; + size_t msb; + const md_info_t *md_info; + md_context_t md_ctx; + + if( ctx->padding != RSA_PKCS_V21 || f_rng == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + switch( hash_id ) + { + case SIG_RSA_MD2: + case SIG_RSA_MD4: + case SIG_RSA_MD5: + hashlen = 16; + break; + + case SIG_RSA_SHA1: + hashlen = 20; + break; + + case SIG_RSA_SHA224: + hashlen = 28; + break; + + case SIG_RSA_SHA256: + hashlen = 32; + break; + + case SIG_RSA_SHA384: + hashlen = 48; + break; + + case SIG_RSA_SHA512: + hashlen = 64; + break; + + default: + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + md_info = md_info_from_type( ctx->hash_id ); + if( md_info == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + hlen = md_get_size( md_info ); + slen = hlen; + + if( olen < hlen + slen + 2 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + memset( sig, 0, olen ); + + msb = mpi_msb( &ctx->N ) - 1; + + // Generate salt of length slen + // + if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 ) + return( POLARSSL_ERR_RSA_RNG_FAILED + ret ); + + // Note: EMSA-PSS encoding is over the length of N - 1 bits + // + msb = mpi_msb( &ctx->N ) - 1; + p += olen - hlen * 2 - 2; + *p++ = 0x01; + memcpy( p, salt, slen ); + p += slen; + + md_init_ctx( &md_ctx, md_info ); + + // Generate H = Hash( M' ) + // + md_starts( &md_ctx ); + md_update( &md_ctx, p, 8 ); + md_update( &md_ctx, hash, hashlen ); + md_update( &md_ctx, salt, slen ); + md_finish( &md_ctx, p ); + + // Compensate for boundary condition when applying mask + // + if( msb % 8 == 0 ) + offset = 1; + + // maskedDB: Apply dbMask to DB + // + mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, &md_ctx ); + + md_free_ctx( &md_ctx ); + + msb = mpi_msb( &ctx->N ) - 1; + sig[0] &= 0xFF >> ( olen * 8 - msb ); + + p += hlen; + *p++ = 0xBC; + + return( ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, sig, sig ) + : rsa_private( ctx, sig, sig ) ); +} +#endif /* POLARSSL_PKCS1_V21 */ + +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function + */ +/* + * Do an RSA operation to sign the message digest + */ +int rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t nb_pad, olen; + unsigned char *p = sig; + + if( ctx->padding != RSA_PKCS_V15 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + switch( hash_id ) + { + case SIG_RSA_RAW: + nb_pad = olen - 3 - hashlen; + break; + + case SIG_RSA_MD2: + case SIG_RSA_MD4: + case SIG_RSA_MD5: + nb_pad = olen - 3 - 34; + break; + + case SIG_RSA_SHA1: + nb_pad = olen - 3 - 35; + break; + + case SIG_RSA_SHA224: + nb_pad = olen - 3 - 47; + break; + + case SIG_RSA_SHA256: + nb_pad = olen - 3 - 51; + break; + + case SIG_RSA_SHA384: + nb_pad = olen - 3 - 67; + break; + + case SIG_RSA_SHA512: + nb_pad = olen - 3 - 83; + break; + + + default: + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + if( ( nb_pad < 8 ) || ( nb_pad > olen ) ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + *p++ = 0; + *p++ = RSA_SIGN; + memset( p, 0xFF, nb_pad ); + p += nb_pad; + *p++ = 0; + + switch( hash_id ) + { + case SIG_RSA_RAW: + memcpy( p, hash, hashlen ); + break; + + case SIG_RSA_MD2: + memcpy( p, ASN1_HASH_MDX, 18 ); + memcpy( p + 18, hash, 16 ); + p[13] = 2; break; + + case SIG_RSA_MD4: + memcpy( p, ASN1_HASH_MDX, 18 ); + memcpy( p + 18, hash, 16 ); + p[13] = 4; break; + + case SIG_RSA_MD5: + memcpy( p, ASN1_HASH_MDX, 18 ); + memcpy( p + 18, hash, 16 ); + p[13] = 5; break; + + case SIG_RSA_SHA1: + memcpy( p, ASN1_HASH_SHA1, 15 ); + memcpy( p + 15, hash, 20 ); + break; + + case SIG_RSA_SHA224: + memcpy( p, ASN1_HASH_SHA2X, 19 ); + memcpy( p + 19, hash, 28 ); + p[1] += 28; p[14] = 4; p[18] += 28; break; + + case SIG_RSA_SHA256: + memcpy( p, ASN1_HASH_SHA2X, 19 ); + memcpy( p + 19, hash, 32 ); + p[1] += 32; p[14] = 1; p[18] += 32; break; + + case SIG_RSA_SHA384: + memcpy( p, ASN1_HASH_SHA2X, 19 ); + memcpy( p + 19, hash, 48 ); + p[1] += 48; p[14] = 2; p[18] += 48; break; + + case SIG_RSA_SHA512: + memcpy( p, ASN1_HASH_SHA2X, 19 ); + memcpy( p + 19, hash, 64 ); + p[1] += 64; p[14] = 3; p[18] += 64; break; + + default: + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + return( ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, sig, sig ) + : rsa_private( ctx, sig, sig ) ); +} + +/* + * Do an RSA operation to sign the message digest + */ +int rsa_pkcs1_sign( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + switch( ctx->padding ) + { + case RSA_PKCS_V15: + return rsa_rsassa_pkcs1_v15_sign( ctx, mode, hash_id, + hashlen, hash, sig ); + +#if defined(POLARSSL_PKCS1_V21) + case RSA_PKCS_V21: + return rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, hash_id, + hashlen, hash, sig ); +#endif + + default: + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(POLARSSL_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function + */ +int rsa_rsassa_pss_verify( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + int ret; + size_t siglen; + unsigned char *p; + unsigned char buf[POLARSSL_MPI_MAX_SIZE]; + unsigned char result[POLARSSL_MD_MAX_SIZE]; + unsigned char zeros[8]; + unsigned int hlen; + size_t slen, msb; + const md_info_t *md_info; + md_context_t md_ctx; + + if( ctx->padding != RSA_PKCS_V21 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + siglen = ctx->len; + + if( siglen < 16 || siglen > sizeof( buf ) ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, sig, buf ) + : rsa_private( ctx, sig, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( buf[siglen - 1] != 0xBC ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + switch( hash_id ) + { + case SIG_RSA_MD2: + case SIG_RSA_MD4: + case SIG_RSA_MD5: + hashlen = 16; + break; + + case SIG_RSA_SHA1: + hashlen = 20; + break; + + case SIG_RSA_SHA224: + hashlen = 28; + break; + + case SIG_RSA_SHA256: + hashlen = 32; + break; + + case SIG_RSA_SHA384: + hashlen = 48; + break; + + case SIG_RSA_SHA512: + hashlen = 64; + break; + + default: + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + } + + md_info = md_info_from_type( ctx->hash_id ); + if( md_info == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + hlen = md_get_size( md_info ); + slen = siglen - hlen - 1; + + memset( zeros, 0, 8 ); + + // Note: EMSA-PSS verification is over the length of N - 1 bits + // + msb = mpi_msb( &ctx->N ) - 1; + + // Compensate for boundary condition when applying mask + // + if( msb % 8 == 0 ) + { + p++; + siglen -= 1; + } + if( buf[0] >> ( 8 - siglen * 8 + msb ) ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + md_init_ctx( &md_ctx, md_info ); + + mgf_mask( p, siglen - hlen - 1, p + siglen - hlen - 1, hlen, &md_ctx ); + + buf[0] &= 0xFF >> ( siglen * 8 - msb ); + + while( *p == 0 && p < buf + siglen ) + p++; + + if( p == buf + siglen || + *p++ != 0x01 ) + { + md_free_ctx( &md_ctx ); + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + } + + slen -= p - buf; + + // Generate H = Hash( M' ) + // + md_starts( &md_ctx ); + md_update( &md_ctx, zeros, 8 ); + md_update( &md_ctx, hash, hashlen ); + md_update( &md_ctx, p, slen ); + md_finish( &md_ctx, result ); + + md_free_ctx( &md_ctx ); + + if( memcmp( p + slen, result, hlen ) == 0 ) + return( 0 ); + else + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); +} +#endif /* POLARSSL_PKCS1_V21 */ + +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function + */ +int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + int ret; + size_t len, siglen; + unsigned char *p, c; + unsigned char buf[POLARSSL_MPI_MAX_SIZE]; + + if( ctx->padding != RSA_PKCS_V15 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + siglen = ctx->len; + + if( siglen < 16 || siglen > sizeof( buf ) ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == RSA_PUBLIC ) + ? rsa_public( ctx, sig, buf ) + : rsa_private( ctx, sig, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( *p++ != 0 || *p++ != RSA_SIGN ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + while( *p != 0 ) + { + if( p >= buf + siglen - 1 || *p != 0xFF ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + p++; + } + p++; + + len = siglen - ( p - buf ); + + if( len == 33 && hash_id == SIG_RSA_SHA1 ) + { + if( memcmp( p, ASN1_HASH_SHA1_ALT, 13 ) == 0 && + memcmp( p + 13, hash, 20 ) == 0 ) + return( 0 ); + else + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + } + if( len == 34 ) + { + c = p[13]; + p[13] = 0; + + if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 ) + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + + if( ( c == 2 && hash_id == SIG_RSA_MD2 ) || + ( c == 4 && hash_id == SIG_RSA_MD4 ) || + ( c == 5 && hash_id == SIG_RSA_MD5 ) ) + { + if( memcmp( p + 18, hash, 16 ) == 0 ) + return( 0 ); + else + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + } + } + + if( len == 35 && hash_id == SIG_RSA_SHA1 ) + { + if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 && + memcmp( p + 15, hash, 20 ) == 0 ) + return( 0 ); + else + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + } + if( ( len == 19 + 28 && p[14] == 4 && hash_id == SIG_RSA_SHA224 ) || + ( len == 19 + 32 && p[14] == 1 && hash_id == SIG_RSA_SHA256 ) || + ( len == 19 + 48 && p[14] == 2 && hash_id == SIG_RSA_SHA384 ) || + ( len == 19 + 64 && p[14] == 3 && hash_id == SIG_RSA_SHA512 ) ) + { + c = p[1] - 17; + p[1] = 17; + p[14] = 0; + + if( p[18] == c && + memcmp( p, ASN1_HASH_SHA2X, 18 ) == 0 && + memcmp( p + 19, hash, c ) == 0 ) + return( 0 ); + else + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + } + + if( len == hashlen && hash_id == SIG_RSA_RAW ) + { + if( memcmp( p, hash, hashlen ) == 0 ) + return( 0 ); + else + return( POLARSSL_ERR_RSA_VERIFY_FAILED ); + } + + return( POLARSSL_ERR_RSA_INVALID_PADDING ); +} + +/* + * Do an RSA operation and check the message digest + */ +int rsa_pkcs1_verify( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + switch( ctx->padding ) + { + case RSA_PKCS_V15: + return rsa_rsassa_pkcs1_v15_verify( ctx, mode, hash_id, + hashlen, hash, sig ); + +#if defined(POLARSSL_PKCS1_V21) + case RSA_PKCS_V21: + return rsa_rsassa_pss_verify( ctx, mode, hash_id, + hashlen, hash, sig ); +#endif + + default: + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + } +} + +/* + * Free the components of an RSA key + */ +void rsa_free( rsa_context *ctx ) +{ + mpi_free( &ctx->RQ ); mpi_free( &ctx->RP ); mpi_free( &ctx->RN ); + mpi_free( &ctx->QP ); mpi_free( &ctx->DQ ); mpi_free( &ctx->DP ); + mpi_free( &ctx->Q ); mpi_free( &ctx->P ); mpi_free( &ctx->D ); + mpi_free( &ctx->E ); mpi_free( &ctx->N ); +} + +#if defined(POLARSSL_SELF_TEST) + +#include "sha1.h" + +/* + * Example RSA-1024 keypair, for test purposes + */ +#define KEY_LEN 128 + +#define RSA_N "9292758453063D803DD603D5E777D788" \ + "8ED1D5BF35786190FA2F23EBC0848AEA" \ + "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ + "7130B9CED7ACDF54CFC7555AC14EEBAB" \ + "93A89813FBF3C4F8066D2D800F7C38A8" \ + "1AE31942917403FF4946B0A83D3D3E05" \ + "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ + "5E94BB77B07507233A0BC7BAC8F90F79" + +#define RSA_E "10001" + +#define RSA_D "24BF6185468786FDD303083D25E64EFC" \ + "66CA472BC44D253102F8B4A9D3BFA750" \ + "91386C0077937FE33FA3252D28855837" \ + "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ + "DF79C5CE07EE72C7F123142198164234" \ + "CABB724CF78B8173B9F880FC86322407" \ + "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ + "071513A1E85B5DFA031F21ECAE91A34D" + +#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ + "2C01CAD19EA484A87EA4377637E75500" \ + "FCB2005C5C7DD6EC4AC023CDA285D796" \ + "C3D9E75E1EFC42488BB4F1D13AC30A57" + +#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ + "E211C2B9E5DB1ED0BF61D0D9899620F4" \ + "910E4168387E3C30AA1E00C339A79508" \ + "8452DD96A9A5EA5D9DCA68DA636032AF" + +#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \ + "3C94D22288ACD763FD8E5600ED4A702D" \ + "F84198A5F06C2E72236AE490C93F07F8" \ + "3CC559CD27BC2D1CA488811730BB5725" + +#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \ + "D8AAEA56749EA28623272E4F7D0592AF" \ + "7C1F1313CAC9471B5C523BFE592F517B" \ + "407A1BD76C164B93DA2D32A383E58357" + +#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \ + "F38D18D2B2F0E2DD275AA977E2BF4411" \ + "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ + "A74206CEC169D74BF5A8C50D6F48EA08" + +#define PT_LEN 24 +#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \ + "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD" + +static int myrand( void *rng_state, unsigned char *output, size_t len ) +{ + size_t i; + + if( rng_state != NULL ) + rng_state = NULL; + + for( i = 0; i < len; ++i ) + output[i] = rand(); + + return( 0 ); +} + +/* + * Checkup routine + */ +int rsa_self_test( int verbose ) +{ + size_t len; + rsa_context rsa; + unsigned char rsa_plaintext[PT_LEN]; + unsigned char rsa_decrypted[PT_LEN]; + unsigned char rsa_ciphertext[KEY_LEN]; +#if defined(POLARSSL_SHA1_C) + unsigned char sha1sum[20]; +#endif + + rsa_init( &rsa, RSA_PKCS_V15, 0 ); + + rsa.len = KEY_LEN; + mpi_read_string( &rsa.N , 16, RSA_N ); + mpi_read_string( &rsa.E , 16, RSA_E ); + mpi_read_string( &rsa.D , 16, RSA_D ); + mpi_read_string( &rsa.P , 16, RSA_P ); + mpi_read_string( &rsa.Q , 16, RSA_Q ); + mpi_read_string( &rsa.DP, 16, RSA_DP ); + mpi_read_string( &rsa.DQ, 16, RSA_DQ ); + mpi_read_string( &rsa.QP, 16, RSA_QP ); + + if( verbose != 0 ) + printf( " RSA key validation: " ); + + if( rsa_check_pubkey( &rsa ) != 0 || + rsa_check_privkey( &rsa ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n PKCS#1 encryption : " ); + + memcpy( rsa_plaintext, RSA_PT, PT_LEN ); + + if( rsa_pkcs1_encrypt( &rsa, &myrand, NULL, RSA_PUBLIC, PT_LEN, + rsa_plaintext, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n PKCS#1 decryption : " ); + + if( rsa_pkcs1_decrypt( &rsa, RSA_PRIVATE, &len, + rsa_ciphertext, rsa_decrypted, + sizeof(rsa_decrypted) ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + +#if defined(POLARSSL_SHA1_C) + if( verbose != 0 ) + printf( "passed\n PKCS#1 data sign : " ); + + sha1( rsa_plaintext, PT_LEN, sha1sum ); + + if( rsa_pkcs1_sign( &rsa, NULL, NULL, RSA_PRIVATE, SIG_RSA_SHA1, 20, + sha1sum, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n PKCS#1 sig. verify: " ); + + if( rsa_pkcs1_verify( &rsa, RSA_PUBLIC, SIG_RSA_SHA1, 20, + sha1sum, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n\n" ); +#endif /* POLARSSL_SHA1_C */ + + rsa_free( &rsa ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/rsa.h b/src/libpolarssl/rsa.h new file mode 100644 index 0000000..f9a0220 --- /dev/null +++ b/src/libpolarssl/rsa.h @@ -0,0 +1,597 @@ +/** + * \file rsa.h + * + * \brief The RSA public-key cryptosystem + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_RSA_H +#define POLARSSL_RSA_H + +#include "bignum.h" + +/* + * RSA Error codes + */ +#define POLARSSL_ERR_RSA_BAD_INPUT_DATA -0x4080 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_RSA_INVALID_PADDING -0x4100 /**< Input data contains invalid padding and is rejected. */ +#define POLARSSL_ERR_RSA_KEY_GEN_FAILED -0x4180 /**< Something failed during generation of a key. */ +#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED -0x4200 /**< Key failed to pass the libraries validity check. */ +#define POLARSSL_ERR_RSA_PUBLIC_FAILED -0x4280 /**< The public key operation failed. */ +#define POLARSSL_ERR_RSA_PRIVATE_FAILED -0x4300 /**< The private key operation failed. */ +#define POLARSSL_ERR_RSA_VERIFY_FAILED -0x4380 /**< The PKCS#1 verification failed. */ +#define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE -0x4400 /**< The output buffer for decryption is not large enough. */ +#define POLARSSL_ERR_RSA_RNG_FAILED -0x4480 /**< The random generator failed to generate non-zeros. */ + +/* + * PKCS#1 constants + */ +#define SIG_RSA_RAW 0 +#define SIG_RSA_MD2 2 +#define SIG_RSA_MD4 3 +#define SIG_RSA_MD5 4 +#define SIG_RSA_SHA1 5 +#define SIG_RSA_SHA224 14 +#define SIG_RSA_SHA256 11 +#define SIG_RSA_SHA384 12 +#define SIG_RSA_SHA512 13 + +#define RSA_PUBLIC 0 +#define RSA_PRIVATE 1 + +#define RSA_PKCS_V15 0 +#define RSA_PKCS_V21 1 + +#define RSA_SIGN 1 +#define RSA_CRYPT 2 + +#define ASN1_STR_CONSTRUCTED_SEQUENCE "\x30" +#define ASN1_STR_NULL "\x05" +#define ASN1_STR_OID "\x06" +#define ASN1_STR_OCTET_STRING "\x04" + +#define OID_DIGEST_ALG_MDX "\x2A\x86\x48\x86\xF7\x0D\x02\x00" +#define OID_HASH_ALG_SHA1 "\x2b\x0e\x03\x02\x1a" +#define OID_HASH_ALG_SHA2X "\x60\x86\x48\x01\x65\x03\x04\x02\x00" + +#define OID_ISO_MEMBER_BODIES "\x2a" +#define OID_ISO_IDENTIFIED_ORG "\x2b" + +/* + * ISO Member bodies OID parts + */ +#define OID_COUNTRY_US "\x86\x48" +#define OID_RSA_DATA_SECURITY "\x86\xf7\x0d" + +/* + * ISO Identified organization OID parts + */ +#define OID_OIW_SECSIG_SHA1 "\x0e\x03\x02\x1a" + +/* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + */ +#define ASN1_HASH_MDX \ +( \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x20" \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x0C" \ + ASN1_STR_OID "\x08" \ + OID_DIGEST_ALG_MDX \ + ASN1_STR_NULL "\x00" \ + ASN1_STR_OCTET_STRING "\x10" \ +) + +#define ASN1_HASH_SHA1 \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x21" \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x09" \ + ASN1_STR_OID "\x05" \ + OID_HASH_ALG_SHA1 \ + ASN1_STR_NULL "\x00" \ + ASN1_STR_OCTET_STRING "\x14" + +#define ASN1_HASH_SHA1_ALT \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x1F" \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x07" \ + ASN1_STR_OID "\x05" \ + OID_HASH_ALG_SHA1 \ + ASN1_STR_OCTET_STRING "\x14" + +#define ASN1_HASH_SHA2X \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x11" \ + ASN1_STR_CONSTRUCTED_SEQUENCE "\x0d" \ + ASN1_STR_OID "\x09" \ + OID_HASH_ALG_SHA2X \ + ASN1_STR_NULL "\x00" \ + ASN1_STR_OCTET_STRING "\x00" + +/** + * \brief RSA context structure + */ +typedef struct +{ + int ver; /*!< always 0 */ + size_t len; /*!< size(N) in chars */ + + mpi N; /*!< public modulus */ + mpi E; /*!< public exponent */ + + mpi D; /*!< private exponent */ + mpi P; /*!< 1st prime factor */ + mpi Q; /*!< 2nd prime factor */ + mpi DP; /*!< D % (P - 1) */ + mpi DQ; /*!< D % (Q - 1) */ + mpi QP; /*!< 1 / (Q % P) */ + + mpi RN; /*!< cached R^2 mod N */ + mpi RP; /*!< cached R^2 mod P */ + mpi RQ; /*!< cached R^2 mod Q */ + + int padding; /*!< RSA_PKCS_V15 for 1.5 padding and + RSA_PKCS_v21 for OAEP/PSS */ + int hash_id; /*!< Hash identifier of md_type_t as + specified in the md.h header file + for the EME-OAEP and EMSA-PSS + encoding */ +} +rsa_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize an RSA context + * + * Note: Set padding to RSA_PKCS_V21 for the RSAES-OAEP + * encryption scheme and the RSASSA-PSS signature scheme. + * + * \param ctx RSA context to be initialized + * \param padding RSA_PKCS_V15 or RSA_PKCS_V21 + * \param hash_id RSA_PKCS_V21 hash identifier + * + * \note The hash_id parameter is actually ignored + * when using RSA_PKCS_V15 padding. + */ +void rsa_init( rsa_context *ctx, + int padding, + int hash_id); + +/** + * \brief Generate an RSA keypair + * + * \param ctx RSA context that will hold the key + * \param f_rng RNG function + * \param p_rng RNG parameter + * \param nbits size of the public key in bits + * \param exponent public exponent (e.g., 65537) + * + * \note rsa_init() must be called beforehand to setup + * the RSA context. + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + */ +int rsa_gen_key( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ); + +/** + * \brief Check a public RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + */ +int rsa_check_pubkey( const rsa_context *ctx ); + +/** + * \brief Check a private RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + */ +int rsa_check_privkey( const rsa_context *ctx ); + +/** + * \brief Do an RSA public key operation + * + * \param ctx RSA context + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note This function does NOT take care of message + * padding. Also, be sure to set input[0] = 0 or assure that + * input is smaller than N. + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_public( rsa_context *ctx, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Do an RSA private key operation + * + * \param ctx RSA context + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_private( rsa_context *ctx, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Generic wrapper to perform a PKCS#1 encryption using the + * mode from the context. Add the message padding, then do an + * RSA operation. + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding) + * \param p_rng RNG parameter + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_pkcs1_encrypt( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Perform a PKCS#1 v1.5 encryption (RSAES-PKCS1-v1_5-ENCRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding) + * \param p_rng RNG parameter + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_rsaes_pkcs1_v15_encrypt( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Perform a PKCS#1 v2.1 OAEP encryption (RSAES-OAEP-ENCRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding) + * \param p_rng RNG parameter + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param label buffer holding the custom label to use + * \param label_len contains the label length + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_rsaes_oaep_encrypt( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Generic wrapper to perform a PKCS#1 decryption using the + * mode from the context. Do an RSA operation, then remove + * the message padding + * + * \param ctx RSA context + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int rsa_pkcs1_decrypt( rsa_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Perform a PKCS#1 v1.5 decryption (RSAES-PKCS1-v1_5-DECRYPT) + * + * \param ctx RSA context + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int rsa_rsaes_pkcs1_v15_decrypt( rsa_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Perform a PKCS#1 v2.1 OAEP decryption (RSAES-OAEP-DECRYPT) + * + * \param ctx RSA context + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param label buffer holding the custom label to use + * \param label_len contains the label length + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int rsa_rsaes_oaep_decrypt( rsa_context *ctx, + int mode, + const unsigned char *label, size_t label_len, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Generic wrapper to perform a PKCS#1 signature using the + * mode from the context. Do a private RSA operation to sign + * a message digest + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding) + * \param p_rng RNG parameter + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} + * \param hashlen message digest length (for SIG_RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an POLARSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note In case of PKCS#1 v2.1 encoding keep in mind that + * the hash_id in the RSA context is the one used for the + * encoding. hash_id in the function call is the type of hash + * that is encoded. According to RFC 3447 it is advised to + * keep both hashes the same. + */ +int rsa_pkcs1_sign( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v1.5 signature (RSASSA-PKCS1-v1_5-SIGN) + * + * \param ctx RSA context + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} + * \param hashlen message digest length (for SIG_RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an POLARSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v2.1 PSS signature (RSASSA-PSS-SIGN) + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding) + * \param p_rng RNG parameter + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} + * \param hashlen message digest length (for SIG_RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an POLARSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note In case of PKCS#1 v2.1 encoding keep in mind that + * the hash_id in the RSA context is the one used for the + * encoding. hash_id in the function call is the type of hash + * that is encoded. According to RFC 3447 it is advised to + * keep both hashes the same. + */ +int rsa_rsassa_pss_sign( rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Generic wrapper to perform a PKCS#1 verification using the + * mode from the context. Do a public RSA operation and check + * the message digest + * + * \param ctx points to an RSA public key + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} + * \param hashlen message digest length (for SIG_RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an POLARSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note In case of PKCS#1 v2.1 encoding keep in mind that + * the hash_id in the RSA context is the one used for the + * verification. hash_id in the function call is the type of hash + * that is verified. According to RFC 3447 it is advised to + * keep both hashes the same. + */ +int rsa_pkcs1_verify( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v1.5 verification (RSASSA-PKCS1-v1_5-VERIFY) + * + * \param ctx points to an RSA public key + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} + * \param hashlen message digest length (for SIG_RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an POLARSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY) + * \brief Do a public RSA and check the message digest + * + * \param ctx points to an RSA public key + * \param mode RSA_PUBLIC or RSA_PRIVATE + * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} + * \param hashlen message digest length (for SIG_RSA_RAW only) + * \param hash buffer holding the message digest + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an POLARSSL_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note In case of PKCS#1 v2.1 encoding keep in mind that + * the hash_id in the RSA context is the one used for the + * verification. hash_id in the function call is the type of hash + * that is verified. According to RFC 3447 it is advised to + * keep both hashes the same. + */ +int rsa_rsassa_pss_verify( rsa_context *ctx, + int mode, + int hash_id, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Free the components of an RSA key + * + * \param ctx RSA Context to free + */ +void rsa_free( rsa_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int rsa_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* rsa.h */ diff --git a/src/libpolarssl/sha1.c b/src/libpolarssl/sha1.c new file mode 100644 index 0000000..c56a6a8 --- /dev/null +++ b/src/libpolarssl/sha1.c @@ -0,0 +1,624 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#include "config.h" + +#if defined(POLARSSL_SHA1_C) + +#include "sha1.h" + +#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST) +#include +#endif + +#if !defined(POLARSSL_SHA1_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * SHA-1 context setup + */ +void sha1_starts( sha1_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +void sha1_process( sha1_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp, W[16], A, B, C, D, E; + + GET_UINT32_BE( W[ 0], data, 0 ); + GET_UINT32_BE( W[ 1], data, 4 ); + GET_UINT32_BE( W[ 2], data, 8 ); + GET_UINT32_BE( W[ 3], data, 12 ); + GET_UINT32_BE( W[ 4], data, 16 ); + GET_UINT32_BE( W[ 5], data, 20 ); + GET_UINT32_BE( W[ 6], data, 24 ); + GET_UINT32_BE( W[ 7], data, 28 ); + GET_UINT32_BE( W[ 8], data, 32 ); + GET_UINT32_BE( W[ 9], data, 36 ); + GET_UINT32_BE( W[10], data, 40 ); + GET_UINT32_BE( W[11], data, 44 ); + GET_UINT32_BE( W[12], data, 48 ); + GET_UINT32_BE( W[13], data, 52 ); + GET_UINT32_BE( W[14], data, 56 ); + GET_UINT32_BE( W[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ +( \ + temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \ + W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \ + ( W[t & 0x0F] = S(temp,1) ) \ +) + +#define P(a,b,c,d,e,x) \ +{ \ + e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P( A, B, C, D, E, W[0] ); + P( E, A, B, C, D, W[1] ); + P( D, E, A, B, C, W[2] ); + P( C, D, E, A, B, W[3] ); + P( B, C, D, E, A, W[4] ); + P( A, B, C, D, E, W[5] ); + P( E, A, B, C, D, W[6] ); + P( D, E, A, B, C, W[7] ); + P( C, D, E, A, B, W[8] ); + P( B, C, D, E, A, W[9] ); + P( A, B, C, D, E, W[10] ); + P( E, A, B, C, D, W[11] ); + P( D, E, A, B, C, W[12] ); + P( C, D, E, A, B, W[13] ); + P( B, C, D, E, A, W[14] ); + P( A, B, C, D, E, W[15] ); + P( E, A, B, C, D, R(16) ); + P( D, E, A, B, C, R(17) ); + P( C, D, E, A, B, R(18) ); + P( B, C, D, E, A, R(19) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P( A, B, C, D, E, R(20) ); + P( E, A, B, C, D, R(21) ); + P( D, E, A, B, C, R(22) ); + P( C, D, E, A, B, R(23) ); + P( B, C, D, E, A, R(24) ); + P( A, B, C, D, E, R(25) ); + P( E, A, B, C, D, R(26) ); + P( D, E, A, B, C, R(27) ); + P( C, D, E, A, B, R(28) ); + P( B, C, D, E, A, R(29) ); + P( A, B, C, D, E, R(30) ); + P( E, A, B, C, D, R(31) ); + P( D, E, A, B, C, R(32) ); + P( C, D, E, A, B, R(33) ); + P( B, C, D, E, A, R(34) ); + P( A, B, C, D, E, R(35) ); + P( E, A, B, C, D, R(36) ); + P( D, E, A, B, C, R(37) ); + P( C, D, E, A, B, R(38) ); + P( B, C, D, E, A, R(39) ); + +#undef K +#undef F + +#define F(x,y,z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P( A, B, C, D, E, R(40) ); + P( E, A, B, C, D, R(41) ); + P( D, E, A, B, C, R(42) ); + P( C, D, E, A, B, R(43) ); + P( B, C, D, E, A, R(44) ); + P( A, B, C, D, E, R(45) ); + P( E, A, B, C, D, R(46) ); + P( D, E, A, B, C, R(47) ); + P( C, D, E, A, B, R(48) ); + P( B, C, D, E, A, R(49) ); + P( A, B, C, D, E, R(50) ); + P( E, A, B, C, D, R(51) ); + P( D, E, A, B, C, R(52) ); + P( C, D, E, A, B, R(53) ); + P( B, C, D, E, A, R(54) ); + P( A, B, C, D, E, R(55) ); + P( E, A, B, C, D, R(56) ); + P( D, E, A, B, C, R(57) ); + P( C, D, E, A, B, R(58) ); + P( B, C, D, E, A, R(59) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P( A, B, C, D, E, R(60) ); + P( E, A, B, C, D, R(61) ); + P( D, E, A, B, C, R(62) ); + P( C, D, E, A, B, R(63) ); + P( B, C, D, E, A, R(64) ); + P( A, B, C, D, E, R(65) ); + P( E, A, B, C, D, R(66) ); + P( D, E, A, B, C, R(67) ); + P( C, D, E, A, B, R(68) ); + P( B, C, D, E, A, R(69) ); + P( A, B, C, D, E, R(70) ); + P( E, A, B, C, D, R(71) ); + P( D, E, A, B, C, R(72) ); + P( C, D, E, A, B, R(73) ); + P( B, C, D, E, A, R(74) ); + P( A, B, C, D, E, R(75) ); + P( E, A, B, C, D, R(76) ); + P( D, E, A, B, C, R(77) ); + P( C, D, E, A, B, R(78) ); + P( B, C, D, E, A, R(79) ); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} + +/* + * SHA-1 process buffer + */ +void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + sha1_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + sha1_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha1_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-1 final digest + */ +void sha1_finish( sha1_context *ctx, unsigned char output[20] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + sha1_update( ctx, sha1_padding, padn ); + sha1_update( ctx, msglen, 8 ); + + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); +} + +#endif /* !POLARSSL_SHA1_ALT */ + +/* + * output = SHA-1( input buffer ) + */ +void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ) +{ + sha1_context ctx; + + sha1_starts( &ctx ); + sha1_update( &ctx, input, ilen ); + sha1_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( sha1_context ) ); +} + +#if defined(POLARSSL_FS_IO) +/* + * output = SHA-1( file contents ) + */ +int sha1_file( const char *path, unsigned char output[20] ) +{ + FILE *f; + size_t n; + sha1_context ctx; + unsigned char buf[1024]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_SHA1_FILE_IO_ERROR ); + + sha1_starts( &ctx ); + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + sha1_update( &ctx, buf, n ); + + sha1_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( sha1_context ) ); + + if( ferror( f ) != 0 ) + { + fclose( f ); + return( POLARSSL_ERR_SHA1_FILE_IO_ERROR ); + } + + fclose( f ); + return( 0 ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * SHA-1 HMAC context setup + */ +void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, size_t keylen ) +{ + size_t i; + unsigned char sum[20]; + + if( keylen > 64 ) + { + sha1( key, keylen, sum ); + keylen = 20; + key = sum; + } + + memset( ctx->ipad, 0x36, 64 ); + memset( ctx->opad, 0x5C, 64 ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + sha1_starts( ctx ); + sha1_update( ctx, ctx->ipad, 64 ); + + memset( sum, 0, sizeof( sum ) ); +} + +/* + * SHA-1 HMAC process buffer + */ +void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, size_t ilen ) +{ + sha1_update( ctx, input, ilen ); +} + +/* + * SHA-1 HMAC final digest + */ +void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] ) +{ + unsigned char tmpbuf[20]; + + sha1_finish( ctx, tmpbuf ); + sha1_starts( ctx ); + sha1_update( ctx, ctx->opad, 64 ); + sha1_update( ctx, tmpbuf, 20 ); + sha1_finish( ctx, output ); + + memset( tmpbuf, 0, sizeof( tmpbuf ) ); +} + +/* + * SHA1 HMAC context reset + */ +void sha1_hmac_reset( sha1_context *ctx ) +{ + sha1_starts( ctx ); + sha1_update( ctx, ctx->ipad, 64 ); +} + +/* + * output = HMAC-SHA-1( hmac key, input buffer ) + */ +void sha1_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[20] ) +{ + sha1_context ctx; + + sha1_hmac_starts( &ctx, key, keylen ); + sha1_hmac_update( &ctx, input, ilen ); + sha1_hmac_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( sha1_context ) ); +} + +#if defined(POLARSSL_SELF_TEST) +/* + * FIPS-180-1 test vectors + */ +static unsigned char sha1_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const int sha1_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha1_test_sum[3][20] = +{ + { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, + 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D }, + { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE, + 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 }, + { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E, + 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F } +}; + +/* + * RFC 2202 test vectors + */ +static unsigned char sha1_hmac_test_key[7][26] = +{ + { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" + "\x0B\x0B\x0B\x0B" }, + { "Jefe" }, + { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA" }, + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19" }, + { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" + "\x0C\x0C\x0C\x0C" }, + { "" }, /* 0xAA 80 times */ + { "" } +}; + +static const int sha1_hmac_test_keylen[7] = +{ + 20, 4, 20, 25, 20, 80, 80 +}; + +static unsigned char sha1_hmac_test_buf[7][74] = +{ + { "Hi There" }, + { "what do ya want for nothing?" }, + { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" }, + { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" }, + { "Test With Truncation" }, + { "Test Using Larger Than Block-Size Key - Hash Key First" }, + { "Test Using Larger Than Block-Size Key and Larger" + " Than One Block-Size Data" } +}; + +static const int sha1_hmac_test_buflen[7] = +{ + 8, 28, 50, 50, 20, 54, 73 +}; + +static const unsigned char sha1_hmac_test_sum[7][20] = +{ + { 0xB6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xE2, 0x8B, + 0xC0, 0xB6, 0xFB, 0x37, 0x8C, 0x8E, 0xF1, 0x46, 0xBE, 0x00 }, + { 0xEF, 0xFC, 0xDF, 0x6A, 0xE5, 0xEB, 0x2F, 0xA2, 0xD2, 0x74, + 0x16, 0xD5, 0xF1, 0x84, 0xDF, 0x9C, 0x25, 0x9A, 0x7C, 0x79 }, + { 0x12, 0x5D, 0x73, 0x42, 0xB9, 0xAC, 0x11, 0xCD, 0x91, 0xA3, + 0x9A, 0xF4, 0x8A, 0xA1, 0x7B, 0x4F, 0x63, 0xF1, 0x75, 0xD3 }, + { 0x4C, 0x90, 0x07, 0xF4, 0x02, 0x62, 0x50, 0xC6, 0xBC, 0x84, + 0x14, 0xF9, 0xBF, 0x50, 0xC8, 0x6C, 0x2D, 0x72, 0x35, 0xDA }, + { 0x4C, 0x1A, 0x03, 0x42, 0x4B, 0x55, 0xE0, 0x7F, 0xE7, 0xF2, + 0x7B, 0xE1 }, + { 0xAA, 0x4A, 0xE5, 0xE1, 0x52, 0x72, 0xD0, 0x0E, 0x95, 0x70, + 0x56, 0x37, 0xCE, 0x8A, 0x3B, 0x55, 0xED, 0x40, 0x21, 0x12 }, + { 0xE8, 0xE9, 0x9D, 0x0F, 0x45, 0x23, 0x7D, 0x78, 0x6D, 0x6B, + 0xBA, 0xA7, 0x96, 0x5C, 0x78, 0x08, 0xBB, 0xFF, 0x1A, 0x91 } +}; + +/* + * Checkup routine + */ +int sha1_self_test( int verbose ) +{ + int i, j, buflen; + unsigned char buf[1024]; + unsigned char sha1sum[20]; + sha1_context ctx; + + /* + * SHA-1 + */ + for( i = 0; i < 3; i++ ) + { + if( verbose != 0 ) + printf( " SHA-1 test #%d: ", i + 1 ); + + sha1_starts( &ctx ); + + if( i == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + sha1_update( &ctx, buf, buflen ); + } + else + sha1_update( &ctx, sha1_test_buf[i], + sha1_test_buflen[i] ); + + sha1_finish( &ctx, sha1sum ); + + if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + printf( " HMAC-SHA-1 test #%d: ", i + 1 ); + + if( i == 5 || i == 6 ) + { + memset( buf, '\xAA', buflen = 80 ); + sha1_hmac_starts( &ctx, buf, buflen ); + } + else + sha1_hmac_starts( &ctx, sha1_hmac_test_key[i], + sha1_hmac_test_keylen[i] ); + + sha1_hmac_update( &ctx, sha1_hmac_test_buf[i], + sha1_hmac_test_buflen[i] ); + + sha1_hmac_finish( &ctx, sha1sum ); + + buflen = ( i == 4 ) ? 12 : 20; + + if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/sha1.h b/src/libpolarssl/sha1.h new file mode 100644 index 0000000..81ea77d --- /dev/null +++ b/src/libpolarssl/sha1.h @@ -0,0 +1,180 @@ +/** + * \file sha1.h + * + * \brief SHA-1 cryptographic hash function + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_SHA1_H +#define POLARSSL_SHA1_H + +#include "config.h" + +#include + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define POLARSSL_ERR_SHA1_FILE_IO_ERROR -0x0076 /**< Read/write error in file. */ + +#if !defined(POLARSSL_SHA1_ALT) +// Regular implementation +// + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ +} +sha1_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void sha1_starts( sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void sha1_finish( sha1_context *ctx, unsigned char output[20] ); + +/* Internal use */ +void sha1_process( sha1_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_SHA1_ALT */ +#include "sha1_alt.h" +#endif /* POLARSSL_SHA1_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ); + +/** + * \brief Output = SHA-1( file contents ) + * + * \param path input file name + * \param output SHA-1 checksum result + * + * \return 0 if successful, or POLARSSL_ERR_SHA1_FILE_IO_ERROR + */ +int sha1_file( const char *path, unsigned char output[20] ); + +/** + * \brief SHA-1 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, size_t keylen ); + +/** + * \brief SHA-1 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-1 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-1 HMAC checksum result + */ +void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] ); + +/** + * \brief SHA-1 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void sha1_hmac_reset( sha1_context *ctx ); + +/** + * \brief Output = HMAC-SHA-1( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-1 result + */ +void sha1_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[20] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int sha1_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha1.h */ diff --git a/src/libpolarssl/sha2.c b/src/libpolarssl/sha2.c new file mode 100644 index 0000000..319d7e8 --- /dev/null +++ b/src/libpolarssl/sha2.c @@ -0,0 +1,705 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The SHA-256 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#include "config.h" + +#if defined(POLARSSL_SHA2_C) + +#include "sha2.h" + +#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST) +#include +#endif + +#if !defined(POLARSSL_SHA2_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * SHA-256 context setup + */ +void sha2_starts( sha2_context *ctx, int is224 ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is224 == 0 ) + { + /* SHA-256 */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + } + else + { + /* SHA-224 */ + ctx->state[0] = 0xC1059ED8; + ctx->state[1] = 0x367CD507; + ctx->state[2] = 0x3070DD17; + ctx->state[3] = 0xF70E5939; + ctx->state[4] = 0xFFC00B31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64F98FA7; + ctx->state[7] = 0xBEFA4FA4; + } + + ctx->is224 = is224; +} + +void sha2_process( sha2_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A, B, C, D, E, F, G, H; + + GET_UINT32_BE( W[ 0], data, 0 ); + GET_UINT32_BE( W[ 1], data, 4 ); + GET_UINT32_BE( W[ 2], data, 8 ); + GET_UINT32_BE( W[ 3], data, 12 ); + GET_UINT32_BE( W[ 4], data, 16 ); + GET_UINT32_BE( W[ 5], data, 20 ); + GET_UINT32_BE( W[ 6], data, 24 ); + GET_UINT32_BE( W[ 7], data, 28 ); + GET_UINT32_BE( W[ 8], data, 32 ); + GET_UINT32_BE( W[ 9], data, 36 ); + GET_UINT32_BE( W[10], data, 40 ); + GET_UINT32_BE( W[11], data, 44 ); + GET_UINT32_BE( W[12], data, 48 ); + GET_UINT32_BE( W[13], data, 52 ); + GET_UINT32_BE( W[14], data, 56 ); + GET_UINT32_BE( W[15], data, 60 ); + +#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define R(t) \ +( \ + W[t] = S1(W[t - 2]) + W[t - 7] + \ + S0(W[t - 15]) + W[t - 16] \ +) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + + P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 ); + P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 ); + P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF ); + P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 ); + P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B ); + P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 ); + P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 ); + P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 ); + P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 ); + P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 ); + P( G, H, A, B, C, D, E, F, W[10], 0x243185BE ); + P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 ); + P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 ); + P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE ); + P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 ); + P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 ); + P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 ); + P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 ); + P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 ); + P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC ); + P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F ); + P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA ); + P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC ); + P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA ); + P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 ); + P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D ); + P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 ); + P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 ); + P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 ); + P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 ); + P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 ); + P( B, C, D, E, F, G, H, A, R(31), 0x14292967 ); + P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 ); + P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 ); + P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC ); + P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 ); + P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 ); + P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB ); + P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E ); + P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 ); + P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 ); + P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B ); + P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 ); + P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 ); + P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 ); + P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 ); + P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 ); + P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 ); + P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 ); + P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 ); + P( G, H, A, B, C, D, E, F, R(50), 0x2748774C ); + P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 ); + P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 ); + P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A ); + P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F ); + P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 ); + P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE ); + P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F ); + P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 ); + P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 ); + P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA ); + P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB ); + P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 ); + P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 ); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} + +/* + * SHA-256 process buffer + */ +void sha2_update( sha2_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen <= 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + sha2_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + sha2_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha2_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-256 final digest + */ +void sha2_finish( sha2_context *ctx, unsigned char output[32] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + sha2_update( ctx, sha2_padding, padn ); + sha2_update( ctx, msglen, 8 ); + + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); + PUT_UINT32_BE( ctx->state[5], output, 20 ); + PUT_UINT32_BE( ctx->state[6], output, 24 ); + + if( ctx->is224 == 0 ) + PUT_UINT32_BE( ctx->state[7], output, 28 ); +} + +#endif /* !POLARSSL_SHA2_ALT */ + +/* + * output = SHA-256( input buffer ) + */ +void sha2( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ) +{ + sha2_context ctx; + + sha2_starts( &ctx, is224 ); + sha2_update( &ctx, input, ilen ); + sha2_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( sha2_context ) ); +} + +#if defined(POLARSSL_FS_IO) +/* + * output = SHA-256( file contents ) + */ +int sha2_file( const char *path, unsigned char output[32], int is224 ) +{ + FILE *f; + size_t n; + sha2_context ctx; + unsigned char buf[1024]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_SHA2_FILE_IO_ERROR ); + + sha2_starts( &ctx, is224 ); + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + sha2_update( &ctx, buf, n ); + + sha2_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( sha2_context ) ); + + if( ferror( f ) != 0 ) + { + fclose( f ); + return( POLARSSL_ERR_SHA2_FILE_IO_ERROR ); + } + + fclose( f ); + return( 0 ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * SHA-256 HMAC context setup + */ +void sha2_hmac_starts( sha2_context *ctx, const unsigned char *key, size_t keylen, + int is224 ) +{ + size_t i; + unsigned char sum[32]; + + if( keylen > 64 ) + { + sha2( key, keylen, sum, is224 ); + keylen = ( is224 ) ? 28 : 32; + key = sum; + } + + memset( ctx->ipad, 0x36, 64 ); + memset( ctx->opad, 0x5C, 64 ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + sha2_starts( ctx, is224 ); + sha2_update( ctx, ctx->ipad, 64 ); + + memset( sum, 0, sizeof( sum ) ); +} + +/* + * SHA-256 HMAC process buffer + */ +void sha2_hmac_update( sha2_context *ctx, const unsigned char *input, size_t ilen ) +{ + sha2_update( ctx, input, ilen ); +} + +/* + * SHA-256 HMAC final digest + */ +void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] ) +{ + int is224, hlen; + unsigned char tmpbuf[32]; + + is224 = ctx->is224; + hlen = ( is224 == 0 ) ? 32 : 28; + + sha2_finish( ctx, tmpbuf ); + sha2_starts( ctx, is224 ); + sha2_update( ctx, ctx->opad, 64 ); + sha2_update( ctx, tmpbuf, hlen ); + sha2_finish( ctx, output ); + + memset( tmpbuf, 0, sizeof( tmpbuf ) ); +} + +/* + * SHA-256 HMAC context reset + */ +void sha2_hmac_reset( sha2_context *ctx ) +{ + sha2_starts( ctx, ctx->is224 ); + sha2_update( ctx, ctx->ipad, 64 ); +} + +/* + * output = HMAC-SHA-256( hmac key, input buffer ) + */ +void sha2_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ) +{ + sha2_context ctx; + + sha2_hmac_starts( &ctx, key, keylen, is224 ); + sha2_hmac_update( &ctx, input, ilen ); + sha2_hmac_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( sha2_context ) ); +} + +#if defined(POLARSSL_SELF_TEST) +/* + * FIPS-180-2 test vectors + */ +static unsigned char sha2_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const int sha2_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha2_test_sum[6][32] = +{ + /* + * SHA-224 test vectors + */ + { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22, + 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3, + 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7, + 0xE3, 0x6C, 0x9D, 0xA7 }, + { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC, + 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50, + 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19, + 0x52, 0x52, 0x25, 0x25 }, + { 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8, + 0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B, + 0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE, + 0x4E, 0xE7, 0xAD, 0x67 }, + + /* + * SHA-256 test vectors + */ + { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, + 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23, + 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, + 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD }, + { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, + 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39, + 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, + 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 }, + { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92, + 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67, + 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E, + 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 } +}; + +/* + * RFC 4231 test vectors + */ +static unsigned char sha2_hmac_test_key[7][26] = +{ + { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" + "\x0B\x0B\x0B\x0B" }, + { "Jefe" }, + { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA" }, + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19" }, + { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" + "\x0C\x0C\x0C\x0C" }, + { "" }, /* 0xAA 131 times */ + { "" } +}; + +static const int sha2_hmac_test_keylen[7] = +{ + 20, 4, 20, 25, 20, 131, 131 +}; + +static unsigned char sha2_hmac_test_buf[7][153] = +{ + { "Hi There" }, + { "what do ya want for nothing?" }, + { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" }, + { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" }, + { "Test With Truncation" }, + { "Test Using Larger Than Block-Size Key - Hash Key First" }, + { "This is a test using a larger than block-size key " + "and a larger than block-size data. The key needs to " + "be hashed before being used by the HMAC algorithm." } +}; + +static const int sha2_hmac_test_buflen[7] = +{ + 8, 28, 50, 50, 20, 54, 152 +}; + +static const unsigned char sha2_hmac_test_sum[14][32] = +{ + /* + * HMAC-SHA-224 test vectors + */ + { 0x89, 0x6F, 0xB1, 0x12, 0x8A, 0xBB, 0xDF, 0x19, + 0x68, 0x32, 0x10, 0x7C, 0xD4, 0x9D, 0xF3, 0x3F, + 0x47, 0xB4, 0xB1, 0x16, 0x99, 0x12, 0xBA, 0x4F, + 0x53, 0x68, 0x4B, 0x22 }, + { 0xA3, 0x0E, 0x01, 0x09, 0x8B, 0xC6, 0xDB, 0xBF, + 0x45, 0x69, 0x0F, 0x3A, 0x7E, 0x9E, 0x6D, 0x0F, + 0x8B, 0xBE, 0xA2, 0xA3, 0x9E, 0x61, 0x48, 0x00, + 0x8F, 0xD0, 0x5E, 0x44 }, + { 0x7F, 0xB3, 0xCB, 0x35, 0x88, 0xC6, 0xC1, 0xF6, + 0xFF, 0xA9, 0x69, 0x4D, 0x7D, 0x6A, 0xD2, 0x64, + 0x93, 0x65, 0xB0, 0xC1, 0xF6, 0x5D, 0x69, 0xD1, + 0xEC, 0x83, 0x33, 0xEA }, + { 0x6C, 0x11, 0x50, 0x68, 0x74, 0x01, 0x3C, 0xAC, + 0x6A, 0x2A, 0xBC, 0x1B, 0xB3, 0x82, 0x62, 0x7C, + 0xEC, 0x6A, 0x90, 0xD8, 0x6E, 0xFC, 0x01, 0x2D, + 0xE7, 0xAF, 0xEC, 0x5A }, + { 0x0E, 0x2A, 0xEA, 0x68, 0xA9, 0x0C, 0x8D, 0x37, + 0xC9, 0x88, 0xBC, 0xDB, 0x9F, 0xCA, 0x6F, 0xA8 }, + { 0x95, 0xE9, 0xA0, 0xDB, 0x96, 0x20, 0x95, 0xAD, + 0xAE, 0xBE, 0x9B, 0x2D, 0x6F, 0x0D, 0xBC, 0xE2, + 0xD4, 0x99, 0xF1, 0x12, 0xF2, 0xD2, 0xB7, 0x27, + 0x3F, 0xA6, 0x87, 0x0E }, + { 0x3A, 0x85, 0x41, 0x66, 0xAC, 0x5D, 0x9F, 0x02, + 0x3F, 0x54, 0xD5, 0x17, 0xD0, 0xB3, 0x9D, 0xBD, + 0x94, 0x67, 0x70, 0xDB, 0x9C, 0x2B, 0x95, 0xC9, + 0xF6, 0xF5, 0x65, 0xD1 }, + + /* + * HMAC-SHA-256 test vectors + */ + { 0xB0, 0x34, 0x4C, 0x61, 0xD8, 0xDB, 0x38, 0x53, + 0x5C, 0xA8, 0xAF, 0xCE, 0xAF, 0x0B, 0xF1, 0x2B, + 0x88, 0x1D, 0xC2, 0x00, 0xC9, 0x83, 0x3D, 0xA7, + 0x26, 0xE9, 0x37, 0x6C, 0x2E, 0x32, 0xCF, 0xF7 }, + { 0x5B, 0xDC, 0xC1, 0x46, 0xBF, 0x60, 0x75, 0x4E, + 0x6A, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xC7, + 0x5A, 0x00, 0x3F, 0x08, 0x9D, 0x27, 0x39, 0x83, + 0x9D, 0xEC, 0x58, 0xB9, 0x64, 0xEC, 0x38, 0x43 }, + { 0x77, 0x3E, 0xA9, 0x1E, 0x36, 0x80, 0x0E, 0x46, + 0x85, 0x4D, 0xB8, 0xEB, 0xD0, 0x91, 0x81, 0xA7, + 0x29, 0x59, 0x09, 0x8B, 0x3E, 0xF8, 0xC1, 0x22, + 0xD9, 0x63, 0x55, 0x14, 0xCE, 0xD5, 0x65, 0xFE }, + { 0x82, 0x55, 0x8A, 0x38, 0x9A, 0x44, 0x3C, 0x0E, + 0xA4, 0xCC, 0x81, 0x98, 0x99, 0xF2, 0x08, 0x3A, + 0x85, 0xF0, 0xFA, 0xA3, 0xE5, 0x78, 0xF8, 0x07, + 0x7A, 0x2E, 0x3F, 0xF4, 0x67, 0x29, 0x66, 0x5B }, + { 0xA3, 0xB6, 0x16, 0x74, 0x73, 0x10, 0x0E, 0xE0, + 0x6E, 0x0C, 0x79, 0x6C, 0x29, 0x55, 0x55, 0x2B }, + { 0x60, 0xE4, 0x31, 0x59, 0x1E, 0xE0, 0xB6, 0x7F, + 0x0D, 0x8A, 0x26, 0xAA, 0xCB, 0xF5, 0xB7, 0x7F, + 0x8E, 0x0B, 0xC6, 0x21, 0x37, 0x28, 0xC5, 0x14, + 0x05, 0x46, 0x04, 0x0F, 0x0E, 0xE3, 0x7F, 0x54 }, + { 0x9B, 0x09, 0xFF, 0xA7, 0x1B, 0x94, 0x2F, 0xCB, + 0x27, 0x63, 0x5F, 0xBC, 0xD5, 0xB0, 0xE9, 0x44, + 0xBF, 0xDC, 0x63, 0x64, 0x4F, 0x07, 0x13, 0x93, + 0x8A, 0x7F, 0x51, 0x53, 0x5C, 0x3A, 0x35, 0xE2 } +}; + +/* + * Checkup routine + */ +int sha2_self_test( int verbose ) +{ + int i, j, k, buflen; + unsigned char buf[1024]; + unsigned char sha2sum[32]; + sha2_context ctx; + + for( i = 0; i < 6; i++ ) + { + j = i % 3; + k = i < 3; + + if( verbose != 0 ) + printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 ); + + sha2_starts( &ctx, k ); + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + sha2_update( &ctx, buf, buflen ); + } + else + sha2_update( &ctx, sha2_test_buf[j], + sha2_test_buflen[j] ); + + sha2_finish( &ctx, sha2sum ); + + if( memcmp( sha2sum, sha2_test_sum[i], 32 - k * 4 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + for( i = 0; i < 14; i++ ) + { + j = i % 7; + k = i < 7; + + if( verbose != 0 ) + printf( " HMAC-SHA-%d test #%d: ", 256 - k * 32, j + 1 ); + + if( j == 5 || j == 6 ) + { + memset( buf, '\xAA', buflen = 131 ); + sha2_hmac_starts( &ctx, buf, buflen, k ); + } + else + sha2_hmac_starts( &ctx, sha2_hmac_test_key[j], + sha2_hmac_test_keylen[j], k ); + + sha2_hmac_update( &ctx, sha2_hmac_test_buf[j], + sha2_hmac_test_buflen[j] ); + + sha2_hmac_finish( &ctx, sha2sum ); + + buflen = ( j == 4 ) ? 16 : 32 - k * 4; + + if( memcmp( sha2sum, sha2_hmac_test_sum[i], buflen ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/sha2.h b/src/libpolarssl/sha2.h new file mode 100644 index 0000000..795299e --- /dev/null +++ b/src/libpolarssl/sha2.h @@ -0,0 +1,188 @@ +/** + * \file sha2.h + * + * \brief SHA-224 and SHA-256 cryptographic hash function + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_SHA2_H +#define POLARSSL_SHA2_H + +#include "config.h" + +#include + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define POLARSSL_ERR_SHA2_FILE_IO_ERROR -0x0078 /**< Read/write error in file. */ + +#if !defined(POLARSSL_SHA2_ALT) +// Regular implementation +// + +/** + * \brief SHA-256 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + + unsigned char ipad[64]; /*!< HMAC: inner padding */ + unsigned char opad[64]; /*!< HMAC: outer padding */ + int is224; /*!< 0 => SHA-256, else SHA-224 */ +} +sha2_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-256 context setup + * + * \param ctx context to be initialized + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha2_starts( sha2_context *ctx, int is224 ); + +/** + * \brief SHA-256 process buffer + * + * \param ctx SHA-256 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha2_update( sha2_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-256 final digest + * + * \param ctx SHA-256 context + * \param output SHA-224/256 checksum result + */ +void sha2_finish( sha2_context *ctx, unsigned char output[32] ); + +/* Internal use */ +void sha2_process( sha2_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_SHA2_ALT */ +#include "sha2_alt.h" +#endif /* POLARSSL_SHA2_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-256( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-224/256 checksum result + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha2( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ); + +/** + * \brief Output = SHA-256( file contents ) + * + * \param path input file name + * \param output SHA-224/256 checksum result + * \param is224 0 = use SHA256, 1 = use SHA224 + * + * \return 0 if successful, or POLARSSL_ERR_SHA2_FILE_IO_ERROR + */ +int sha2_file( const char *path, unsigned char output[32], int is224 ); + +/** + * \brief SHA-256 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha2_hmac_starts( sha2_context *ctx, const unsigned char *key, size_t keylen, + int is224 ); + +/** + * \brief SHA-256 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha2_hmac_update( sha2_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-256 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-224/256 HMAC checksum result + */ +void sha2_hmac_finish( sha2_context *ctx, unsigned char output[32] ); + +/** + * \brief SHA-256 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void sha2_hmac_reset( sha2_context *ctx ); + +/** + * \brief Output = HMAC-SHA-256( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-224/256 result + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void sha2_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int sha2_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha2.h */ diff --git a/src/libpolarssl/sha4.c b/src/libpolarssl/sha4.c new file mode 100644 index 0000000..092ed95 --- /dev/null +++ b/src/libpolarssl/sha4.c @@ -0,0 +1,760 @@ +/* + * FIPS-180-2 compliant SHA-384/512 implementation + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The SHA-512 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#include "config.h" + +#if defined(POLARSSL_SHA4_C) + +#include "sha4.h" + +#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST) +#include +#endif + +#if !defined(POLARSSL_SHA4_ALT) + +/* + * 64-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT64_BE +#define GET_UINT64_BE(n,b,i) \ +{ \ + (n) = ( (uint64_t) (b)[(i) ] << 56 ) \ + | ( (uint64_t) (b)[(i) + 1] << 48 ) \ + | ( (uint64_t) (b)[(i) + 2] << 40 ) \ + | ( (uint64_t) (b)[(i) + 3] << 32 ) \ + | ( (uint64_t) (b)[(i) + 4] << 24 ) \ + | ( (uint64_t) (b)[(i) + 5] << 16 ) \ + | ( (uint64_t) (b)[(i) + 6] << 8 ) \ + | ( (uint64_t) (b)[(i) + 7] ); \ +} +#endif + +#ifndef PUT_UINT64_BE +#define PUT_UINT64_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 56 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 7] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Round constants + */ +static const uint64_t K[80] = +{ + UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD), + UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC), + UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019), + UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118), + UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE), + UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2), + UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1), + UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694), + UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3), + UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65), + UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483), + UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5), + UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210), + UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4), + UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725), + UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70), + UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926), + UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF), + UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8), + UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B), + UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001), + UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30), + UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910), + UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8), + UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53), + UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8), + UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB), + UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3), + UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60), + UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC), + UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9), + UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B), + UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207), + UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178), + UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6), + UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B), + UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493), + UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C), + UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A), + UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817) +}; + +/* + * SHA-512 context setup + */ +void sha4_starts( sha4_context *ctx, int is384 ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is384 == 0 ) + { + /* SHA-512 */ + ctx->state[0] = UL64(0x6A09E667F3BCC908); + ctx->state[1] = UL64(0xBB67AE8584CAA73B); + ctx->state[2] = UL64(0x3C6EF372FE94F82B); + ctx->state[3] = UL64(0xA54FF53A5F1D36F1); + ctx->state[4] = UL64(0x510E527FADE682D1); + ctx->state[5] = UL64(0x9B05688C2B3E6C1F); + ctx->state[6] = UL64(0x1F83D9ABFB41BD6B); + ctx->state[7] = UL64(0x5BE0CD19137E2179); + } + else + { + /* SHA-384 */ + ctx->state[0] = UL64(0xCBBB9D5DC1059ED8); + ctx->state[1] = UL64(0x629A292A367CD507); + ctx->state[2] = UL64(0x9159015A3070DD17); + ctx->state[3] = UL64(0x152FECD8F70E5939); + ctx->state[4] = UL64(0x67332667FFC00B31); + ctx->state[5] = UL64(0x8EB44A8768581511); + ctx->state[6] = UL64(0xDB0C2E0D64F98FA7); + ctx->state[7] = UL64(0x47B5481DBEFA4FA4); + } + + ctx->is384 = is384; +} + +static void sha4_process( sha4_context *ctx, const unsigned char data[128] ) +{ + int i; + uint64_t temp1, temp2, W[80]; + uint64_t A, B, C, D, E, F, G, H; + +#define SHR(x,n) (x >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (64 - n))) + +#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) +#define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x, 6)) + +#define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) +#define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + for( i = 0; i < 16; i++ ) + { + GET_UINT64_BE( W[i], data, i << 3 ); + } + + for( ; i < 80; i++ ) + { + W[i] = S1(W[i - 2]) + W[i - 7] + + S0(W[i - 15]) + W[i - 16]; + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + i = 0; + + do + { + P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++; + P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++; + P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++; + P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++; + P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++; + P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++; + P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++; + P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++; + } + while( i < 80 ); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} + +/* + * SHA-512 process buffer + */ +void sha4_update( sha4_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + unsigned int left; + + if( ilen <= 0 ) + return; + + left = (unsigned int) (ctx->total[0] & 0x7F); + fill = 128 - left; + + ctx->total[0] += (uint64_t) ilen; + + if( ctx->total[0] < (uint64_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + sha4_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 128 ) + { + sha4_process( ctx, input ); + input += 128; + ilen -= 128; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha4_padding[128] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-512 final digest + */ +void sha4_finish( sha4_context *ctx, unsigned char output[64] ) +{ + size_t last, padn; + uint64_t high, low; + unsigned char msglen[16]; + + high = ( ctx->total[0] >> 61 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT64_BE( high, msglen, 0 ); + PUT_UINT64_BE( low, msglen, 8 ); + + last = (size_t)( ctx->total[0] & 0x7F ); + padn = ( last < 112 ) ? ( 112 - last ) : ( 240 - last ); + + sha4_update( ctx, sha4_padding, padn ); + sha4_update( ctx, msglen, 16 ); + + PUT_UINT64_BE( ctx->state[0], output, 0 ); + PUT_UINT64_BE( ctx->state[1], output, 8 ); + PUT_UINT64_BE( ctx->state[2], output, 16 ); + PUT_UINT64_BE( ctx->state[3], output, 24 ); + PUT_UINT64_BE( ctx->state[4], output, 32 ); + PUT_UINT64_BE( ctx->state[5], output, 40 ); + + if( ctx->is384 == 0 ) + { + PUT_UINT64_BE( ctx->state[6], output, 48 ); + PUT_UINT64_BE( ctx->state[7], output, 56 ); + } +} + +#endif /* !POLARSSL_SHA4_ALT */ + +/* + * output = SHA-512( input buffer ) + */ +void sha4( const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ) +{ + sha4_context ctx; + + sha4_starts( &ctx, is384 ); + sha4_update( &ctx, input, ilen ); + sha4_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( sha4_context ) ); +} + +#if defined(POLARSSL_FS_IO) +/* + * output = SHA-512( file contents ) + */ +int sha4_file( const char *path, unsigned char output[64], int is384 ) +{ + FILE *f; + size_t n; + sha4_context ctx; + unsigned char buf[1024]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_SHA4_FILE_IO_ERROR ); + + sha4_starts( &ctx, is384 ); + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + sha4_update( &ctx, buf, n ); + + sha4_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( sha4_context ) ); + + if( ferror( f ) != 0 ) + { + fclose( f ); + return( POLARSSL_ERR_SHA4_FILE_IO_ERROR ); + } + + fclose( f ); + return( 0 ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * SHA-512 HMAC context setup + */ +void sha4_hmac_starts( sha4_context *ctx, const unsigned char *key, size_t keylen, + int is384 ) +{ + size_t i; + unsigned char sum[64]; + + if( keylen > 128 ) + { + sha4( key, keylen, sum, is384 ); + keylen = ( is384 ) ? 48 : 64; + key = sum; + } + + memset( ctx->ipad, 0x36, 128 ); + memset( ctx->opad, 0x5C, 128 ); + + for( i = 0; i < keylen; i++ ) + { + ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); + ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); + } + + sha4_starts( ctx, is384 ); + sha4_update( ctx, ctx->ipad, 128 ); + + memset( sum, 0, sizeof( sum ) ); +} + +/* + * SHA-512 HMAC process buffer + */ +void sha4_hmac_update( sha4_context *ctx, + const unsigned char *input, size_t ilen ) +{ + sha4_update( ctx, input, ilen ); +} + +/* + * SHA-512 HMAC final digest + */ +void sha4_hmac_finish( sha4_context *ctx, unsigned char output[64] ) +{ + int is384, hlen; + unsigned char tmpbuf[64]; + + is384 = ctx->is384; + hlen = ( is384 == 0 ) ? 64 : 48; + + sha4_finish( ctx, tmpbuf ); + sha4_starts( ctx, is384 ); + sha4_update( ctx, ctx->opad, 128 ); + sha4_update( ctx, tmpbuf, hlen ); + sha4_finish( ctx, output ); + + memset( tmpbuf, 0, sizeof( tmpbuf ) ); +} + +/* + * SHA-512 HMAC context reset + */ +void sha4_hmac_reset( sha4_context *ctx ) +{ + sha4_starts( ctx, ctx->is384 ); + sha4_update( ctx, ctx->ipad, 128 ); +} + +/* + * output = HMAC-SHA-512( hmac key, input buffer ) + */ +void sha4_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ) +{ + sha4_context ctx; + + sha4_hmac_starts( &ctx, key, keylen, is384 ); + sha4_hmac_update( &ctx, input, ilen ); + sha4_hmac_finish( &ctx, output ); + + memset( &ctx, 0, sizeof( sha4_context ) ); +} + +#if defined(POLARSSL_SELF_TEST) + +/* + * FIPS-180-2 test vectors + */ +static unsigned char sha4_test_buf[3][113] = +{ + { "abc" }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" }, + { "" } +}; + +static const int sha4_test_buflen[3] = +{ + 3, 112, 1000 +}; + +static const unsigned char sha4_test_sum[6][64] = +{ + /* + * SHA-384 test vectors + */ + { 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B, + 0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07, + 0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63, + 0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED, + 0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23, + 0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 }, + { 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8, + 0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47, + 0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2, + 0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12, + 0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9, + 0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39 }, + { 0x9D, 0x0E, 0x18, 0x09, 0x71, 0x64, 0x74, 0xCB, + 0x08, 0x6E, 0x83, 0x4E, 0x31, 0x0A, 0x4A, 0x1C, + 0xED, 0x14, 0x9E, 0x9C, 0x00, 0xF2, 0x48, 0x52, + 0x79, 0x72, 0xCE, 0xC5, 0x70, 0x4C, 0x2A, 0x5B, + 0x07, 0xB8, 0xB3, 0xDC, 0x38, 0xEC, 0xC4, 0xEB, + 0xAE, 0x97, 0xDD, 0xD8, 0x7F, 0x3D, 0x89, 0x85 }, + + /* + * SHA-512 test vectors + */ + { 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, + 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31, + 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, + 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A, + 0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8, + 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD, + 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E, + 0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F }, + { 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA, + 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F, + 0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1, + 0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18, + 0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4, + 0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A, + 0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54, + 0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 }, + { 0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64, + 0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15, 0xB4, 0x63, + 0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28, + 0x56, 0x32, 0xA8, 0x03, 0xAF, 0xA9, 0x73, 0xEB, + 0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A, + 0x4C, 0xB0, 0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B, + 0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E, + 0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B } +}; + +/* + * RFC 4231 test vectors + */ +static unsigned char sha4_hmac_test_key[7][26] = +{ + { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" + "\x0B\x0B\x0B\x0B" }, + { "Jefe" }, + { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA" }, + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19" }, + { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" + "\x0C\x0C\x0C\x0C" }, + { "" }, /* 0xAA 131 times */ + { "" } +}; + +static const int sha4_hmac_test_keylen[7] = +{ + 20, 4, 20, 25, 20, 131, 131 +}; + +static unsigned char sha4_hmac_test_buf[7][153] = +{ + { "Hi There" }, + { "what do ya want for nothing?" }, + { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" }, + { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" }, + { "Test With Truncation" }, + { "Test Using Larger Than Block-Size Key - Hash Key First" }, + { "This is a test using a larger than block-size key " + "and a larger than block-size data. The key needs to " + "be hashed before being used by the HMAC algorithm." } +}; + +static const int sha4_hmac_test_buflen[7] = +{ + 8, 28, 50, 50, 20, 54, 152 +}; + +static const unsigned char sha4_hmac_test_sum[14][64] = +{ + /* + * HMAC-SHA-384 test vectors + */ + { 0xAF, 0xD0, 0x39, 0x44, 0xD8, 0x48, 0x95, 0x62, + 0x6B, 0x08, 0x25, 0xF4, 0xAB, 0x46, 0x90, 0x7F, + 0x15, 0xF9, 0xDA, 0xDB, 0xE4, 0x10, 0x1E, 0xC6, + 0x82, 0xAA, 0x03, 0x4C, 0x7C, 0xEB, 0xC5, 0x9C, + 0xFA, 0xEA, 0x9E, 0xA9, 0x07, 0x6E, 0xDE, 0x7F, + 0x4A, 0xF1, 0x52, 0xE8, 0xB2, 0xFA, 0x9C, 0xB6 }, + { 0xAF, 0x45, 0xD2, 0xE3, 0x76, 0x48, 0x40, 0x31, + 0x61, 0x7F, 0x78, 0xD2, 0xB5, 0x8A, 0x6B, 0x1B, + 0x9C, 0x7E, 0xF4, 0x64, 0xF5, 0xA0, 0x1B, 0x47, + 0xE4, 0x2E, 0xC3, 0x73, 0x63, 0x22, 0x44, 0x5E, + 0x8E, 0x22, 0x40, 0xCA, 0x5E, 0x69, 0xE2, 0xC7, + 0x8B, 0x32, 0x39, 0xEC, 0xFA, 0xB2, 0x16, 0x49 }, + { 0x88, 0x06, 0x26, 0x08, 0xD3, 0xE6, 0xAD, 0x8A, + 0x0A, 0xA2, 0xAC, 0xE0, 0x14, 0xC8, 0xA8, 0x6F, + 0x0A, 0xA6, 0x35, 0xD9, 0x47, 0xAC, 0x9F, 0xEB, + 0xE8, 0x3E, 0xF4, 0xE5, 0x59, 0x66, 0x14, 0x4B, + 0x2A, 0x5A, 0xB3, 0x9D, 0xC1, 0x38, 0x14, 0xB9, + 0x4E, 0x3A, 0xB6, 0xE1, 0x01, 0xA3, 0x4F, 0x27 }, + { 0x3E, 0x8A, 0x69, 0xB7, 0x78, 0x3C, 0x25, 0x85, + 0x19, 0x33, 0xAB, 0x62, 0x90, 0xAF, 0x6C, 0xA7, + 0x7A, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9C, + 0xC5, 0x57, 0x7C, 0x6E, 0x1F, 0x57, 0x3B, 0x4E, + 0x68, 0x01, 0xDD, 0x23, 0xC4, 0xA7, 0xD6, 0x79, + 0xCC, 0xF8, 0xA3, 0x86, 0xC6, 0x74, 0xCF, 0xFB }, + { 0x3A, 0xBF, 0x34, 0xC3, 0x50, 0x3B, 0x2A, 0x23, + 0xA4, 0x6E, 0xFC, 0x61, 0x9B, 0xAE, 0xF8, 0x97 }, + { 0x4E, 0xCE, 0x08, 0x44, 0x85, 0x81, 0x3E, 0x90, + 0x88, 0xD2, 0xC6, 0x3A, 0x04, 0x1B, 0xC5, 0xB4, + 0x4F, 0x9E, 0xF1, 0x01, 0x2A, 0x2B, 0x58, 0x8F, + 0x3C, 0xD1, 0x1F, 0x05, 0x03, 0x3A, 0xC4, 0xC6, + 0x0C, 0x2E, 0xF6, 0xAB, 0x40, 0x30, 0xFE, 0x82, + 0x96, 0x24, 0x8D, 0xF1, 0x63, 0xF4, 0x49, 0x52 }, + { 0x66, 0x17, 0x17, 0x8E, 0x94, 0x1F, 0x02, 0x0D, + 0x35, 0x1E, 0x2F, 0x25, 0x4E, 0x8F, 0xD3, 0x2C, + 0x60, 0x24, 0x20, 0xFE, 0xB0, 0xB8, 0xFB, 0x9A, + 0xDC, 0xCE, 0xBB, 0x82, 0x46, 0x1E, 0x99, 0xC5, + 0xA6, 0x78, 0xCC, 0x31, 0xE7, 0x99, 0x17, 0x6D, + 0x38, 0x60, 0xE6, 0x11, 0x0C, 0x46, 0x52, 0x3E }, + + /* + * HMAC-SHA-512 test vectors + */ + { 0x87, 0xAA, 0x7C, 0xDE, 0xA5, 0xEF, 0x61, 0x9D, + 0x4F, 0xF0, 0xB4, 0x24, 0x1A, 0x1D, 0x6C, 0xB0, + 0x23, 0x79, 0xF4, 0xE2, 0xCE, 0x4E, 0xC2, 0x78, + 0x7A, 0xD0, 0xB3, 0x05, 0x45, 0xE1, 0x7C, 0xDE, + 0xDA, 0xA8, 0x33, 0xB7, 0xD6, 0xB8, 0xA7, 0x02, + 0x03, 0x8B, 0x27, 0x4E, 0xAE, 0xA3, 0xF4, 0xE4, + 0xBE, 0x9D, 0x91, 0x4E, 0xEB, 0x61, 0xF1, 0x70, + 0x2E, 0x69, 0x6C, 0x20, 0x3A, 0x12, 0x68, 0x54 }, + { 0x16, 0x4B, 0x7A, 0x7B, 0xFC, 0xF8, 0x19, 0xE2, + 0xE3, 0x95, 0xFB, 0xE7, 0x3B, 0x56, 0xE0, 0xA3, + 0x87, 0xBD, 0x64, 0x22, 0x2E, 0x83, 0x1F, 0xD6, + 0x10, 0x27, 0x0C, 0xD7, 0xEA, 0x25, 0x05, 0x54, + 0x97, 0x58, 0xBF, 0x75, 0xC0, 0x5A, 0x99, 0x4A, + 0x6D, 0x03, 0x4F, 0x65, 0xF8, 0xF0, 0xE6, 0xFD, + 0xCA, 0xEA, 0xB1, 0xA3, 0x4D, 0x4A, 0x6B, 0x4B, + 0x63, 0x6E, 0x07, 0x0A, 0x38, 0xBC, 0xE7, 0x37 }, + { 0xFA, 0x73, 0xB0, 0x08, 0x9D, 0x56, 0xA2, 0x84, + 0xEF, 0xB0, 0xF0, 0x75, 0x6C, 0x89, 0x0B, 0xE9, + 0xB1, 0xB5, 0xDB, 0xDD, 0x8E, 0xE8, 0x1A, 0x36, + 0x55, 0xF8, 0x3E, 0x33, 0xB2, 0x27, 0x9D, 0x39, + 0xBF, 0x3E, 0x84, 0x82, 0x79, 0xA7, 0x22, 0xC8, + 0x06, 0xB4, 0x85, 0xA4, 0x7E, 0x67, 0xC8, 0x07, + 0xB9, 0x46, 0xA3, 0x37, 0xBE, 0xE8, 0x94, 0x26, + 0x74, 0x27, 0x88, 0x59, 0xE1, 0x32, 0x92, 0xFB }, + { 0xB0, 0xBA, 0x46, 0x56, 0x37, 0x45, 0x8C, 0x69, + 0x90, 0xE5, 0xA8, 0xC5, 0xF6, 0x1D, 0x4A, 0xF7, + 0xE5, 0x76, 0xD9, 0x7F, 0xF9, 0x4B, 0x87, 0x2D, + 0xE7, 0x6F, 0x80, 0x50, 0x36, 0x1E, 0xE3, 0xDB, + 0xA9, 0x1C, 0xA5, 0xC1, 0x1A, 0xA2, 0x5E, 0xB4, + 0xD6, 0x79, 0x27, 0x5C, 0xC5, 0x78, 0x80, 0x63, + 0xA5, 0xF1, 0x97, 0x41, 0x12, 0x0C, 0x4F, 0x2D, + 0xE2, 0xAD, 0xEB, 0xEB, 0x10, 0xA2, 0x98, 0xDD }, + { 0x41, 0x5F, 0xAD, 0x62, 0x71, 0x58, 0x0A, 0x53, + 0x1D, 0x41, 0x79, 0xBC, 0x89, 0x1D, 0x87, 0xA6 }, + { 0x80, 0xB2, 0x42, 0x63, 0xC7, 0xC1, 0xA3, 0xEB, + 0xB7, 0x14, 0x93, 0xC1, 0xDD, 0x7B, 0xE8, 0xB4, + 0x9B, 0x46, 0xD1, 0xF4, 0x1B, 0x4A, 0xEE, 0xC1, + 0x12, 0x1B, 0x01, 0x37, 0x83, 0xF8, 0xF3, 0x52, + 0x6B, 0x56, 0xD0, 0x37, 0xE0, 0x5F, 0x25, 0x98, + 0xBD, 0x0F, 0xD2, 0x21, 0x5D, 0x6A, 0x1E, 0x52, + 0x95, 0xE6, 0x4F, 0x73, 0xF6, 0x3F, 0x0A, 0xEC, + 0x8B, 0x91, 0x5A, 0x98, 0x5D, 0x78, 0x65, 0x98 }, + { 0xE3, 0x7B, 0x6A, 0x77, 0x5D, 0xC8, 0x7D, 0xBA, + 0xA4, 0xDF, 0xA9, 0xF9, 0x6E, 0x5E, 0x3F, 0xFD, + 0xDE, 0xBD, 0x71, 0xF8, 0x86, 0x72, 0x89, 0x86, + 0x5D, 0xF5, 0xA3, 0x2D, 0x20, 0xCD, 0xC9, 0x44, + 0xB6, 0x02, 0x2C, 0xAC, 0x3C, 0x49, 0x82, 0xB1, + 0x0D, 0x5E, 0xEB, 0x55, 0xC3, 0xE4, 0xDE, 0x15, + 0x13, 0x46, 0x76, 0xFB, 0x6D, 0xE0, 0x44, 0x60, + 0x65, 0xC9, 0x74, 0x40, 0xFA, 0x8C, 0x6A, 0x58 } +}; + +/* + * Checkup routine + */ +int sha4_self_test( int verbose ) +{ + int i, j, k, buflen; + unsigned char buf[1024]; + unsigned char sha4sum[64]; + sha4_context ctx; + + for( i = 0; i < 6; i++ ) + { + j = i % 3; + k = i < 3; + + if( verbose != 0 ) + printf( " SHA-%d test #%d: ", 512 - k * 128, j + 1 ); + + sha4_starts( &ctx, k ); + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + sha4_update( &ctx, buf, buflen ); + } + else + sha4_update( &ctx, sha4_test_buf[j], + sha4_test_buflen[j] ); + + sha4_finish( &ctx, sha4sum ); + + if( memcmp( sha4sum, sha4_test_sum[i], 64 - k * 16 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + for( i = 0; i < 14; i++ ) + { + j = i % 7; + k = i < 7; + + if( verbose != 0 ) + printf( " HMAC-SHA-%d test #%d: ", 512 - k * 128, j + 1 ); + + if( j == 5 || j == 6 ) + { + memset( buf, '\xAA', buflen = 131 ); + sha4_hmac_starts( &ctx, buf, buflen, k ); + } + else + sha4_hmac_starts( &ctx, sha4_hmac_test_key[j], + sha4_hmac_test_keylen[j], k ); + + sha4_hmac_update( &ctx, sha4_hmac_test_buf[j], + sha4_hmac_test_buflen[j] ); + + sha4_hmac_finish( &ctx, sha4sum ); + + buflen = ( j == 4 ) ? 16 : 64 - k * 16; + + if( memcmp( sha4sum, sha4_hmac_test_sum[i], buflen ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/sha4.h b/src/libpolarssl/sha4.h new file mode 100644 index 0000000..7b0cdf6 --- /dev/null +++ b/src/libpolarssl/sha4.h @@ -0,0 +1,186 @@ +/** + * \file sha4.h + * + * \brief SHA-384 and SHA-512 cryptographic hash function + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_SHA4_H +#define POLARSSL_SHA4_H + +#include "config.h" + +#include + +#if defined(_MSC_VER) || defined(__WATCOMC__) + #define UL64(x) x##ui64 + typedef unsigned __int64 uint64_t; +#else + #include + #define UL64(x) x##ULL +#endif + +#define POLARSSL_ERR_SHA4_FILE_IO_ERROR -0x007A /**< Read/write error in file. */ + +#if !defined(POLARSSL_SHA1_ALT) +// Regular implementation +// + +/** + * \brief SHA-512 context structure + */ +typedef struct +{ + uint64_t total[2]; /*!< number of bytes processed */ + uint64_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[128]; /*!< data block being processed */ + + unsigned char ipad[128]; /*!< HMAC: inner padding */ + unsigned char opad[128]; /*!< HMAC: outer padding */ + int is384; /*!< 0 => SHA-512, else SHA-384 */ +} +sha4_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-512 context setup + * + * \param ctx context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha4_starts( sha4_context *ctx, int is384 ); + +/** + * \brief SHA-512 process buffer + * + * \param ctx SHA-512 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha4_update( sha4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-512 final digest + * + * \param ctx SHA-512 context + * \param output SHA-384/512 checksum result + */ +void sha4_finish( sha4_context *ctx, unsigned char output[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_SHA4_ALT */ +#include "sha4_alt.h" +#endif /* POLARSSL_SHA4_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-512( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-384/512 checksum result + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha4( const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ); + +/** + * \brief Output = SHA-512( file contents ) + * + * \param path input file name + * \param output SHA-384/512 checksum result + * \param is384 0 = use SHA512, 1 = use SHA384 + * + * \return 0 if successful, or POLARSSL_ERR_SHA4_FILE_IO_ERROR + */ +int sha4_file( const char *path, unsigned char output[64], int is384 ); + +/** + * \brief SHA-512 HMAC context setup + * + * \param ctx HMAC context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + * \param key HMAC secret key + * \param keylen length of the HMAC key + */ +void sha4_hmac_starts( sha4_context *ctx, const unsigned char *key, size_t keylen, + int is384 ); + +/** + * \brief SHA-512 HMAC process buffer + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void sha4_hmac_update( sha4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-512 HMAC final digest + * + * \param ctx HMAC context + * \param output SHA-384/512 HMAC checksum result + */ +void sha4_hmac_finish( sha4_context *ctx, unsigned char output[64] ); + +/** + * \brief SHA-512 HMAC context reset + * + * \param ctx HMAC context to be reset + */ +void sha4_hmac_reset( sha4_context *ctx ); + +/** + * \brief Output = HMAC-SHA-512( hmac key, input buffer ) + * + * \param key HMAC secret key + * \param keylen length of the HMAC key + * \param input buffer holding the data + * \param ilen length of the input data + * \param output HMAC-SHA-384/512 result + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void sha4_hmac( const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int sha4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* sha4.h */ diff --git a/src/libpolarssl/ssl.h b/src/libpolarssl/ssl.h new file mode 100644 index 0000000..fa644fe --- /dev/null +++ b/src/libpolarssl/ssl.h @@ -0,0 +1,1140 @@ +/** + * \file ssl.h + * + * \brief SSL/TLS functions. + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_SSL_H +#define POLARSSL_SSL_H + +#include + +#include "net.h" +#include "rsa.h" +#include "md5.h" +#include "sha1.h" +#include "sha2.h" +#include "sha4.h" +#include "x509.h" +#include "config.h" + +#if defined(POLARSSL_DHM_C) +#include "dhm.h" +#endif + +#if defined(POLARSSL_ZLIB_SUPPORT) +#include "zlib.h" +#endif + +#if defined(_MSC_VER) && !defined(inline) +#define inline _inline +#else +#if defined(__ARMCC_VERSION) && !defined(inline) +#define inline __inline +#endif /* __ARMCC_VERSION */ +#endif /*_MSC_VER */ + +/* + * SSL Error codes + */ +#define POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE -0x7080 /**< The requested feature is not available. */ +#define POLARSSL_ERR_SSL_BAD_INPUT_DATA -0x7100 /**< Bad input parameters to function. */ +#define POLARSSL_ERR_SSL_INVALID_MAC -0x7180 /**< Verification of the message MAC failed. */ +#define POLARSSL_ERR_SSL_INVALID_RECORD -0x7200 /**< An invalid SSL record was received. */ +#define POLARSSL_ERR_SSL_CONN_EOF -0x7280 /**< The connection indicated an EOF. */ +#define POLARSSL_ERR_SSL_UNKNOWN_CIPHER -0x7300 /**< An unknown cipher was received. */ +#define POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN -0x7380 /**< The server has no ciphersuites in common with the client. */ +#define POLARSSL_ERR_SSL_NO_SESSION_FOUND -0x7400 /**< No session to recover was found. */ +#define POLARSSL_ERR_SSL_NO_CLIENT_CERTIFICATE -0x7480 /**< No client certification received from the client, but required by the authentication mode. */ +#define POLARSSL_ERR_SSL_CERTIFICATE_TOO_LARGE -0x7500 /**< Our own certificate(s) is/are too large to send in an SSL message.*/ +#define POLARSSL_ERR_SSL_CERTIFICATE_REQUIRED -0x7580 /**< The own certificate is not set, but needed by the server. */ +#define POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED -0x7600 /**< The own private key is not set, but needed. */ +#define POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED -0x7680 /**< No CA Chain is set, but required to operate. */ +#define POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE -0x7700 /**< An unexpected message was received from our peer. */ +#define POLARSSL_ERR_SSL_FATAL_ALERT_MESSAGE -0x7780 /**< A fatal alert message was received from our peer. */ +#define POLARSSL_ERR_SSL_PEER_VERIFY_FAILED -0x7800 /**< Verification of our peer failed. */ +#define POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY -0x7880 /**< The peer notified us that the connection is going to be closed. */ +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO -0x7900 /**< Processing of the ClientHello handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO -0x7980 /**< Processing of the ServerHello handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE -0x7A00 /**< Processing of the Certificate handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST -0x7A80 /**< Processing of the CertificateRequest handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE -0x7B00 /**< Processing of the ServerKeyExchange handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO_DONE -0x7B80 /**< Processing of the ServerHelloDone handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE -0x7C00 /**< Processing of the ClientKeyExchange handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_DHM_RP -0x7C80 /**< Processing of the ClientKeyExchange handshake message failed in DHM Read Public. */ +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_DHM_CS -0x7D00 /**< Processing of the ClientKeyExchange handshake message failed in DHM Calculate Secret. */ +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY -0x7D80 /**< Processing of the CertificateVerify handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC -0x7E00 /**< Processing of the ChangeCipherSpec handshake message failed. */ +#define POLARSSL_ERR_SSL_BAD_HS_FINISHED -0x7E80 /**< Processing of the Finished handshake message failed. */ +#define POLARSSL_ERR_SSL_MALLOC_FAILED -0x7F00 /**< Memory allocation failed */ +#define POLARSSL_ERR_SSL_HW_ACCEL_FAILED -0x7F80 /**< Hardware acceleration function returned with error */ +#define POLARSSL_ERR_SSL_HW_ACCEL_FALLTHROUGH -0x6F80 /**< Hardware acceleration function skipped / left alone data */ +#define POLARSSL_ERR_SSL_COMPRESSION_FAILED -0x6F00 /**< Processing of the compression / decompression failed */ +#define POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION -0x6E80 /**< Handshake protocol not within min/max boundaries */ + +/* + * Various constants + */ +#define SSL_MAJOR_VERSION_3 3 +#define SSL_MINOR_VERSION_0 0 /*!< SSL v3.0 */ +#define SSL_MINOR_VERSION_1 1 /*!< TLS v1.0 */ +#define SSL_MINOR_VERSION_2 2 /*!< TLS v1.1 */ +#define SSL_MINOR_VERSION_3 3 /*!< TLS v1.2 */ + +#define SSL_IS_CLIENT 0 +#define SSL_IS_SERVER 1 +#define SSL_COMPRESS_NULL 0 +#define SSL_COMPRESS_DEFLATE 1 + +#define SSL_VERIFY_NONE 0 +#define SSL_VERIFY_OPTIONAL 1 +#define SSL_VERIFY_REQUIRED 2 + +#define SSL_INITIAL_HANDSHAKE 0 +#define SSL_RENEGOTIATION 1 + +#define SSL_LEGACY_RENEGOTIATION 0 +#define SSL_SECURE_RENEGOTIATION 1 + +#define SSL_RENEGOTIATION_DISABLED 0 +#define SSL_RENEGOTIATION_ENABLED 1 + +#define SSL_LEGACY_NO_RENEGOTIATION 0 +#define SSL_LEGACY_ALLOW_RENEGOTIATION 1 +#define SSL_LEGACY_BREAK_HANDSHAKE 2 + +/* + * Size of the input / output buffer. + * Note: the RFC defines the default size of SSL / TLS messages. If you + * change the value here, other clients / servers may not be able to + * communicate with you anymore. Only change this value if you control + * both sides of the connection and have it reduced at both sides! + */ +#if !defined(POLARSSL_CONFIG_OPTIONS) +#define SSL_MAX_CONTENT_LEN 16384 /**< Size of the input / output buffer */ +#endif /* !POLARSSL_CONFIG_OPTIONS */ + +/* + * Allow an extra 512 bytes for the record header + * and encryption overhead (counter + MAC + padding) + * and allow for a maximum of 1024 of compression expansion if + * enabled. + */ +#if defined(POLARSSL_ZLIB_SUPPORT) +#define SSL_COMPRESSION_ADD 1024 +#else +#define SSL_COMPRESSION_ADD 0 +#endif + +#define SSL_BUFFER_LEN (SSL_MAX_CONTENT_LEN + SSL_COMPRESSION_ADD + 512) + +/* + * Supported ciphersuites (Official IANA names) + */ +#define TLS_RSA_WITH_NULL_MD5 0x01 /**< Weak! */ +#define TLS_RSA_WITH_NULL_SHA 0x02 /**< Weak! */ +#define TLS_RSA_WITH_NULL_SHA256 0x3B /**< Weak! */ +#define TLS_RSA_WITH_DES_CBC_SHA 0x09 /**< Weak! Not in TLS 1.2 */ +#define TLS_DHE_RSA_WITH_DES_CBC_SHA 0x15 /**< Weak! Not in TLS 1.2 */ + +#define TLS_RSA_WITH_RC4_128_MD5 0x04 +#define TLS_RSA_WITH_RC4_128_SHA 0x05 + +#define TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x0A +#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x16 + +#define TLS_RSA_WITH_AES_128_CBC_SHA 0x2F +#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x33 +#define TLS_RSA_WITH_AES_256_CBC_SHA 0x35 +#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x39 +#define TLS_RSA_WITH_AES_128_CBC_SHA256 0x3C /**< TLS 1.2 */ +#define TLS_RSA_WITH_AES_256_CBC_SHA256 0x3D /**< TLS 1.2 */ +#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x67 /**< TLS 1.2 */ +#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x6B /**< TLS 1.2 */ + +#define TLS_RSA_WITH_CAMELLIA_128_CBC_SHA 0x41 +#define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x45 +#define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA 0x84 +#define TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x88 +#define TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xBA /**< TLS 1.2 */ +#define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xBE /**< TLS 1.2 */ +#define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 0xC0 /**< TLS 1.2 */ +#define TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 0xC4 /**< TLS 1.2 */ + +#define TLS_RSA_WITH_AES_128_GCM_SHA256 0x9C +#define TLS_RSA_WITH_AES_256_GCM_SHA384 0x9D +#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x9E +#define TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x9F + +#define SSL_EMPTY_RENEGOTIATION_INFO 0xFF /**< renegotiation info ext */ + +/* + * Supported Signature and Hash algorithms (For TLS 1.2) + */ +#define SSL_HASH_NONE 0 +#define SSL_HASH_MD5 1 +#define SSL_HASH_SHA1 2 +#define SSL_HASH_SHA224 3 +#define SSL_HASH_SHA256 4 +#define SSL_HASH_SHA384 5 +#define SSL_HASH_SHA512 6 + +#define SSL_SIG_RSA 1 + +/* + * Client Certificate Types + */ +#define SSL_CERT_TYPE_RSA_SIGN 1 + +/* + * Message, alert and handshake types + */ +#define SSL_MSG_CHANGE_CIPHER_SPEC 20 +#define SSL_MSG_ALERT 21 +#define SSL_MSG_HANDSHAKE 22 +#define SSL_MSG_APPLICATION_DATA 23 + +#define SSL_ALERT_LEVEL_WARNING 1 +#define SSL_ALERT_LEVEL_FATAL 2 + +#define SSL_ALERT_MSG_CLOSE_NOTIFY 0 /* 0x00 */ +#define SSL_ALERT_MSG_UNEXPECTED_MESSAGE 10 /* 0x0A */ +#define SSL_ALERT_MSG_BAD_RECORD_MAC 20 /* 0x14 */ +#define SSL_ALERT_MSG_DECRYPTION_FAILED 21 /* 0x15 */ +#define SSL_ALERT_MSG_RECORD_OVERFLOW 22 /* 0x16 */ +#define SSL_ALERT_MSG_DECOMPRESSION_FAILURE 30 /* 0x1E */ +#define SSL_ALERT_MSG_HANDSHAKE_FAILURE 40 /* 0x28 */ +#define SSL_ALERT_MSG_NO_CERT 41 /* 0x29 */ +#define SSL_ALERT_MSG_BAD_CERT 42 /* 0x2A */ +#define SSL_ALERT_MSG_UNSUPPORTED_CERT 43 /* 0x2B */ +#define SSL_ALERT_MSG_CERT_REVOKED 44 /* 0x2C */ +#define SSL_ALERT_MSG_CERT_EXPIRED 45 /* 0x2D */ +#define SSL_ALERT_MSG_CERT_UNKNOWN 46 /* 0x2E */ +#define SSL_ALERT_MSG_ILLEGAL_PARAMETER 47 /* 0x2F */ +#define SSL_ALERT_MSG_UNKNOWN_CA 48 /* 0x30 */ +#define SSL_ALERT_MSG_ACCESS_DENIED 49 /* 0x31 */ +#define SSL_ALERT_MSG_DECODE_ERROR 50 /* 0x32 */ +#define SSL_ALERT_MSG_DECRYPT_ERROR 51 /* 0x33 */ +#define SSL_ALERT_MSG_EXPORT_RESTRICTION 60 /* 0x3C */ +#define SSL_ALERT_MSG_PROTOCOL_VERSION 70 /* 0x46 */ +#define SSL_ALERT_MSG_INSUFFICIENT_SECURITY 71 /* 0x47 */ +#define SSL_ALERT_MSG_INTERNAL_ERROR 80 /* 0x50 */ +#define SSL_ALERT_MSG_USER_CANCELED 90 /* 0x5A */ +#define SSL_ALERT_MSG_NO_RENEGOTIATION 100 /* 0x64 */ +#define SSL_ALERT_MSG_UNSUPPORTED_EXT 110 /* 0x6E */ +#define SSL_ALERT_MSG_UNRECOGNIZED_NAME 112 /* 0x70 */ + +#define SSL_HS_HELLO_REQUEST 0 +#define SSL_HS_CLIENT_HELLO 1 +#define SSL_HS_SERVER_HELLO 2 +#define SSL_HS_CERTIFICATE 11 +#define SSL_HS_SERVER_KEY_EXCHANGE 12 +#define SSL_HS_CERTIFICATE_REQUEST 13 +#define SSL_HS_SERVER_HELLO_DONE 14 +#define SSL_HS_CERTIFICATE_VERIFY 15 +#define SSL_HS_CLIENT_KEY_EXCHANGE 16 +#define SSL_HS_FINISHED 20 + +/* + * TLS extensions + */ +#define TLS_EXT_SERVERNAME 0 +#define TLS_EXT_SERVERNAME_HOSTNAME 0 + +#define TLS_EXT_SIG_ALG 13 + +#define TLS_EXT_RENEGOTIATION_INFO 0xFF01 + + +/* + * Generic function pointers for allowing external RSA private key + * implementations. + */ +typedef int (*rsa_decrypt_func)( void *ctx, int mode, size_t *olen, + const unsigned char *input, unsigned char *output, + size_t output_max_len ); +typedef int (*rsa_sign_func)( void *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + int mode, int hash_id, unsigned int hashlen, + const unsigned char *hash, unsigned char *sig ); +typedef size_t (*rsa_key_len_func)( void *ctx ); + +/* + * SSL state machine + */ +typedef enum +{ + SSL_HELLO_REQUEST, + SSL_CLIENT_HELLO, + SSL_SERVER_HELLO, + SSL_SERVER_CERTIFICATE, + SSL_SERVER_KEY_EXCHANGE, + SSL_CERTIFICATE_REQUEST, + SSL_SERVER_HELLO_DONE, + SSL_CLIENT_CERTIFICATE, + SSL_CLIENT_KEY_EXCHANGE, + SSL_CERTIFICATE_VERIFY, + SSL_CLIENT_CHANGE_CIPHER_SPEC, + SSL_CLIENT_FINISHED, + SSL_SERVER_CHANGE_CIPHER_SPEC, + SSL_SERVER_FINISHED, + SSL_FLUSH_BUFFERS, + SSL_HANDSHAKE_WRAPUP, + SSL_HANDSHAKE_OVER +} +ssl_states; + +typedef struct _ssl_session ssl_session; +typedef struct _ssl_context ssl_context; +typedef struct _ssl_transform ssl_transform; +typedef struct _ssl_handshake_params ssl_handshake_params; + +/* + * This structure is used for storing current session data. + */ +struct _ssl_session +{ + time_t start; /*!< starting time */ + int ciphersuite; /*!< chosen ciphersuite */ + int compression; /*!< chosen compression */ + size_t length; /*!< session id length */ + unsigned char id[32]; /*!< session identifier */ + unsigned char master[48]; /*!< the master secret */ + x509_cert *peer_cert; /*!< peer X.509 cert chain */ +}; + +/* + * This structure contains a full set of runtime transform parameters + * either in negotiation or active. + */ +struct _ssl_transform +{ + /* + * Session specific crypto layer + */ + unsigned int keylen; /*!< symmetric key length */ + size_t minlen; /*!< min. ciphertext length */ + size_t ivlen; /*!< IV length */ + size_t fixed_ivlen; /*!< Fixed part of IV (AEAD) */ + size_t maclen; /*!< MAC length */ + + unsigned char iv_enc[16]; /*!< IV (encryption) */ + unsigned char iv_dec[16]; /*!< IV (decryption) */ + + unsigned char mac_enc[32]; /*!< MAC (encryption) */ + unsigned char mac_dec[32]; /*!< MAC (decryption) */ + + uint32_t ctx_enc[136]; /*!< encryption context */ + uint32_t ctx_dec[136]; /*!< decryption context */ + + /* + * Session specific compression layer + */ +#if defined(POLARSSL_ZLIB_SUPPORT) + z_stream ctx_deflate; /*!< compression context */ + z_stream ctx_inflate; /*!< decompression context */ +#endif +}; + +/* + * This structure contains the parameters only needed during handshake. + */ +struct _ssl_handshake_params +{ + /* + * Handshake specific crypto variables + */ + int sig_alg; /*!< Signature algorithm */ + int cert_type; /*!< Requested cert type */ + int verify_sig_alg; /*!< Signature algorithm for verify */ +#if defined(POLARSSL_DHM_C) + dhm_context dhm_ctx; /*!< DHM key exchange */ +#endif + + /* + * Checksum contexts + */ + md5_context fin_md5; + sha1_context fin_sha1; + sha2_context fin_sha2; + sha4_context fin_sha4; + + void (*update_checksum)(ssl_context *, unsigned char *, size_t); + void (*calc_verify)(ssl_context *, unsigned char *); + void (*calc_finished)(ssl_context *, unsigned char *, int); + int (*tls_prf)(unsigned char *, size_t, char *, + unsigned char *, size_t, + unsigned char *, size_t); + + size_t pmslen; /*!< premaster length */ + + unsigned char randbytes[64]; /*!< random bytes */ + unsigned char premaster[POLARSSL_MPI_MAX_SIZE]; + /*!< premaster secret */ + + int resume; /*!< session resume indicator*/ +}; + +struct _ssl_context +{ + /* + * Miscellaneous + */ + int state; /*!< SSL handshake: current state */ + int renegotiation; /*!< Initial or renegotiation */ + + int major_ver; /*!< equal to SSL_MAJOR_VERSION_3 */ + int minor_ver; /*!< either 0 (SSL3) or 1 (TLS1.0) */ + + int max_major_ver; /*!< max. major version from client */ + int max_minor_ver; /*!< max. minor version from client */ + int min_major_ver; /*!< min. major version accepted */ + int min_minor_ver; /*!< min. minor version accepted */ + + /* + * Callbacks (RNG, debug, I/O, verification) + */ + int (*f_rng)(void *, unsigned char *, size_t); + void (*f_dbg)(void *, int, const char *); + int (*f_recv)(void *, unsigned char *, size_t); + int (*f_send)(void *, const unsigned char *, size_t); + int (*f_vrfy)(void *, x509_cert *, int, int *); + int (*f_get_cache)(void *, ssl_session *); + int (*f_set_cache)(void *, const ssl_session *); + int (*f_sni)(void *, ssl_context *, const unsigned char *, size_t); + + void *p_rng; /*!< context for the RNG function */ + void *p_dbg; /*!< context for the debug function */ + void *p_recv; /*!< context for reading operations */ + void *p_send; /*!< context for writing operations */ + void *p_vrfy; /*!< context for verification */ + void *p_get_cache; /*!< context for cache retrieval */ + void *p_set_cache; /*!< context for cache store */ + void *p_sni; /*!< context for SNI extension */ + void *p_hw_data; /*!< context for HW acceleration */ + + /* + * Session layer + */ + ssl_session *session_in; /*!< current session data (in) */ + ssl_session *session_out; /*!< current session data (out) */ + ssl_session *session; /*!< negotiated session data */ + ssl_session *session_negotiate; /*!< session data in negotiation */ + + ssl_handshake_params *handshake; /*!< params required only during + the handshake process */ + + /* + * Record layer transformations + */ + ssl_transform *transform_in; /*!< current transform params (in) */ + ssl_transform *transform_out; /*!< current transform params (in) */ + ssl_transform *transform; /*!< negotiated transform params */ + ssl_transform *transform_negotiate; /*!< transform params in negotiation */ + + /* + * Record layer (incoming data) + */ + unsigned char *in_ctr; /*!< 64-bit incoming message counter */ + unsigned char *in_hdr; /*!< 5-byte record header (in_ctr+8) */ + unsigned char *in_msg; /*!< the message contents (in_hdr+5) */ + unsigned char *in_offt; /*!< read offset in application data */ + + int in_msgtype; /*!< record header: message type */ + size_t in_msglen; /*!< record header: message length */ + size_t in_left; /*!< amount of data read so far */ + + size_t in_hslen; /*!< current handshake message length */ + int nb_zero; /*!< # of 0-length encrypted messages */ + + /* + * Record layer (outgoing data) + */ + unsigned char *out_ctr; /*!< 64-bit outgoing message counter */ + unsigned char *out_hdr; /*!< 5-byte record header (out_ctr+8) */ + unsigned char *out_msg; /*!< the message contents (out_hdr+32)*/ + + int out_msgtype; /*!< record header: message type */ + size_t out_msglen; /*!< record header: message length */ + size_t out_left; /*!< amount of data not yet written */ + + /* + * PKI layer + */ + void *rsa_key; /*!< own RSA private key */ + rsa_decrypt_func rsa_decrypt; /*!< function for RSA decrypt*/ + rsa_sign_func rsa_sign; /*!< function for RSA sign */ + rsa_key_len_func rsa_key_len; /*!< function for RSA key len*/ + + x509_cert *own_cert; /*!< own X.509 certificate */ + x509_cert *ca_chain; /*!< own trusted CA chain */ + x509_crl *ca_crl; /*!< trusted CA CRLs */ + const char *peer_cn; /*!< expected peer CN */ + + /* + * User settings + */ + int endpoint; /*!< 0: client, 1: server */ + int authmode; /*!< verification mode */ + int client_auth; /*!< flag for client auth. */ + int verify_result; /*!< verification result */ + int disable_renegotiation; /*!< enable/disable renegotiation */ + int allow_legacy_renegotiation; /*!< allow legacy renegotiation */ + const int **ciphersuites; /*!< allowed ciphersuites / version */ + +#if defined(POLARSSL_DHM_C) + mpi dhm_P; /*!< prime modulus for DHM */ + mpi dhm_G; /*!< generator for DHM */ +#endif + + /* + * TLS extensions + */ + unsigned char *hostname; + size_t hostname_len; + + /* + * Secure renegotiation + */ + int secure_renegotiation; /*!< does peer support legacy or + secure renegotiation */ + size_t verify_data_len; /*!< length of verify data stored */ + char own_verify_data[36]; /*!< previous handshake verify data */ + char peer_verify_data[36]; /*!< previous handshake verify data */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern const int ssl_default_ciphersuites[]; + +#if defined(POLARSSL_SSL_HW_RECORD_ACCEL) +extern int (*ssl_hw_record_init)(ssl_context *ssl, + const unsigned char *key_enc, const unsigned char *key_dec, + const unsigned char *iv_enc, const unsigned char *iv_dec, + const unsigned char *mac_enc, const unsigned char *mac_dec); +extern int (*ssl_hw_record_reset)(ssl_context *ssl); +extern int (*ssl_hw_record_write)(ssl_context *ssl); +extern int (*ssl_hw_record_read)(ssl_context *ssl); +extern int (*ssl_hw_record_finish)(ssl_context *ssl); +#endif + +/** + * \brief Returns the list of ciphersuites supported by the SSL/TLS module. + * + * \return a statically allocated array of ciphersuites, the last + * entry is 0. + */ +static inline const int *ssl_list_ciphersuites( void ) +{ + return ssl_default_ciphersuites; +} + +/** + * \brief Return the name of the ciphersuite associated with the given + * ID + * + * \param ciphersuite_id SSL ciphersuite ID + * + * \return a string containing the ciphersuite name + */ +const char *ssl_get_ciphersuite_name( const int ciphersuite_id ); + +/** + * \brief Return the ID of the ciphersuite associated with the given + * name + * + * \param ciphersuite_name SSL ciphersuite name + * + * \return the ID with the ciphersuite or 0 if not found + */ +int ssl_get_ciphersuite_id( const char *ciphersuite_name ); + +/** + * \brief Initialize an SSL context + * + * \param ssl SSL context + * + * \return 0 if successful, or POLARSSL_ERR_SSL_MALLOC_FAILED if + * memory allocation failed + */ +int ssl_init( ssl_context *ssl ); + +/** + * \brief Reset an already initialized SSL context for re-use + * while retaining application-set variables, function + * pointers and data. + * + * \param ssl SSL context + * \return 0 if successful, or POLASSL_ERR_SSL_MALLOC_FAILED, + POLARSSL_ERR_SSL_HW_ACCEL_FAILED or + * POLARSSL_ERR_SSL_COMPRESSION_FAILED + */ +int ssl_session_reset( ssl_context *ssl ); + +/** + * \brief Set the current endpoint type + * + * \param ssl SSL context + * \param endpoint must be SSL_IS_CLIENT or SSL_IS_SERVER + */ +void ssl_set_endpoint( ssl_context *ssl, int endpoint ); + +/** + * \brief Set the certificate verification mode + * + * \param ssl SSL context + * \param authmode can be: + * + * SSL_VERIFY_NONE: peer certificate is not checked (default), + * this is insecure and SHOULD be avoided. + * + * SSL_VERIFY_OPTIONAL: peer certificate is checked, however the + * handshake continues even if verification failed; + * ssl_get_verify_result() can be called after the + * handshake is complete. + * + * SSL_VERIFY_REQUIRED: peer *must* present a valid certificate, + * handshake is aborted if verification failed. + */ +void ssl_set_authmode( ssl_context *ssl, int authmode ); + +/** + * \brief Set the verification callback (Optional). + * + * If set, the verify callback is called for each + * certificate in the chain. For implementation + * information, please see \c x509parse_verify() + * + * \param ssl SSL context + * \param f_vrfy verification function + * \param p_vrfy verification parameter + */ +void ssl_set_verify( ssl_context *ssl, + int (*f_vrfy)(void *, x509_cert *, int, int *), + void *p_vrfy ); + +/** + * \brief Set the random number generator callback + * + * \param ssl SSL context + * \param f_rng RNG function + * \param p_rng RNG parameter + */ +void ssl_set_rng( ssl_context *ssl, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Set the debug callback + * + * \param ssl SSL context + * \param f_dbg debug function + * \param p_dbg debug parameter + */ +void ssl_set_dbg( ssl_context *ssl, + void (*f_dbg)(void *, int, const char *), + void *p_dbg ); + +/** + * \brief Set the underlying BIO read and write callbacks + * + * \param ssl SSL context + * \param f_recv read callback + * \param p_recv read parameter + * \param f_send write callback + * \param p_send write parameter + */ +void ssl_set_bio( ssl_context *ssl, + int (*f_recv)(void *, unsigned char *, size_t), void *p_recv, + int (*f_send)(void *, const unsigned char *, size_t), void *p_send ); + +/** + * \brief Set the session cache callbacks (server-side only) + * If not set, no session resuming is done. + * + * The session cache has the responsibility to check for stale + * entries based on timeout. See RFC 5246 for recommendations. + * + * Warning: session.peer_cert is cleared by the SSL/TLS layer on + * connection shutdown, so do not cache the pointer! Either set + * it to NULL or make a full copy of the certificate. + * + * The get callback is called once during the initial handshake + * to enable session resuming. The get function has the + * following parameters: (void *parameter, ssl_session *session) + * If a valid entry is found, it should fill the master of + * the session object with the cached values and return 0, + * return 1 otherwise. Optionally peer_cert can be set as well + * if it is properly present in cache entry. + * + * The set callback is called once during the initial handshake + * to enable session resuming after the entire handshake has + * been finished. The set function has the following parameters: + * (void *parameter, const ssl_session *session). The function + * should create a cache entry for future retrieval based on + * the data in the session structure and should keep in mind + * that the ssl_session object presented (and all its referenced + * data) is cleared by the SSL/TLS layer when the connection is + * terminated. It is recommended to add metadata to determine if + * an entry is still valid in the future. Return 0 if + * successfully cached, return 1 otherwise. + * + * \param ssl SSL context + * \param f_get_cache session get callback + * \param p_get_cache session get parameter + * \param f_set_cache session set callback + * \param p_set_cache session set parameter + */ +void ssl_set_session_cache( ssl_context *ssl, + int (*f_get_cache)(void *, ssl_session *), void *p_get_cache, + int (*f_set_cache)(void *, const ssl_session *), void *p_set_cache ); + +/** + * \brief Request resumption of session (client-side only) + * Session data is copied from presented session structure. + * + * Warning: session.peer_cert is cleared by the SSL/TLS layer on + * connection shutdown, so do not cache the pointer! Either set + * it to NULL or make a full copy of the certificate when + * storing the session for use in this function. + * + * \param ssl SSL context + * \param session session context + */ +void ssl_set_session( ssl_context *ssl, const ssl_session *session ); + +/** + * \brief Set the list of allowed ciphersuites + * (Default: ssl_default_ciphersuites) + * (Overrides all version specific lists) + * + * \param ssl SSL context + * \param ciphersuites 0-terminated list of allowed ciphersuites + */ +void ssl_set_ciphersuites( ssl_context *ssl, const int *ciphersuites ); + +/** + * \brief Set the list of allowed ciphersuites for a specific + * version of the protocol. + * (Default: ssl_default_ciphersuites) + * (Only useful on the server side) + * + * \param ssl SSL context + * \param ciphersuites 0-terminated list of allowed ciphersuites + * \param major Major version number (only SSL_MAJOR_VERSION_3 + * supported) + * \param minor Minor version number (SSL_MINOR_VERSION_0, + * SSL_MINOR_VERSION_1 and SSL_MINOR_VERSION_2, + * SSL_MINOR_VERSION_3 supported) + */ +void ssl_set_ciphersuites_for_version( ssl_context *ssl, + const int *ciphersuites, + int major, int minor ); + +/** + * \brief Set the data required to verify peer certificate + * + * \param ssl SSL context + * \param ca_chain trusted CA chain (meaning all fully trusted top-level CAs) + * \param ca_crl trusted CA CRLs + * \param peer_cn expected peer CommonName (or NULL) + */ +void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain, + x509_crl *ca_crl, const char *peer_cn ); + +/** + * \brief Set own certificate chain and private key + * + * Note: own_cert should contain IN order from the bottom + * up your certificate chain. The top certificate (self-signed) + * can be omitted. + * + * \param ssl SSL context + * \param own_cert own public certificate chain + * \param rsa_key own private RSA key + */ +void ssl_set_own_cert( ssl_context *ssl, x509_cert *own_cert, + rsa_context *rsa_key ); + +/** + * \brief Set own certificate and alternate non-PolarSSL private + * key and handling callbacks, such as the PKCS#11 wrappers + * or any other external private key handler. + * (see the respective RSA functions in rsa.h for documentation + * of the callback parameters, with the only change being + * that the rsa_context * is a void * in the callbacks) + * + * Note: own_cert should contain IN order from the bottom + * up your certificate chain. The top certificate (self-signed) + * can be omitted. + * + * \param ssl SSL context + * \param own_cert own public certificate chain + * \param rsa_key alternate implementation private RSA key + * \param rsa_decrypt_func alternate implementation of \c rsa_pkcs1_decrypt() + * \param rsa_sign_func alternate implementation of \c rsa_pkcs1_sign() + * \param rsa_key_len_func function returning length of RSA key in bytes + */ +void ssl_set_own_cert_alt( ssl_context *ssl, x509_cert *own_cert, + void *rsa_key, + rsa_decrypt_func rsa_decrypt, + rsa_sign_func rsa_sign, + rsa_key_len_func rsa_key_len ); + +#if defined(POLARSSL_DHM_C) +/** + * \brief Set the Diffie-Hellman public P and G values, + * read as hexadecimal strings (server-side only) + * (Default: POLARSSL_DHM_RFC5114_MODP_1024_[PG]) + * + * \param ssl SSL context + * \param dhm_P Diffie-Hellman-Merkle modulus + * \param dhm_G Diffie-Hellman-Merkle generator + * + * \return 0 if successful + */ +int ssl_set_dh_param( ssl_context *ssl, const char *dhm_P, const char *dhm_G ); + +/** + * \brief Set the Diffie-Hellman public P and G values, + * read from existing context (server-side only) + * + * \param ssl SSL context + * \param dhm_ctx Diffie-Hellman-Merkle context + * + * \return 0 if successful + */ +int ssl_set_dh_param_ctx( ssl_context *ssl, dhm_context *dhm_ctx ); +#endif + +/** + * \brief Set hostname for ServerName TLS extension + * (client-side only) + * + * + * \param ssl SSL context + * \param hostname the server hostname + * + * \return 0 if successful or POLARSSL_ERR_SSL_MALLOC_FAILED + */ +int ssl_set_hostname( ssl_context *ssl, const char *hostname ); + +/** + * \brief Set server side ServerName TLS extension callback + * (optional, server-side only). + * + * If set, the ServerName callback is called whenever the + * server receives a ServerName TLS extension from the client + * during a handshake. The ServerName callback has the + * following parameters: (void *parameter, ssl_context *ssl, + * const unsigned char *hostname, size_t len). If a suitable + * certificate is found, the callback should set the + * certificate and key to use with ssl_set_own_cert() (and + * possibly adjust the CA chain as well) and return 0. The + * callback should return -1 to abort the handshake at this + * point. + * + * \param ssl SSL context + * \param f_sni verification function + * \param p_sni verification parameter + */ +void ssl_set_sni( ssl_context *ssl, + int (*f_sni)(void *, ssl_context *, const unsigned char *, + size_t), + void *p_sni ); + +/** + * \brief Set the maximum supported version sent from the client side + * + * \param ssl SSL context + * \param major Major version number (only SSL_MAJOR_VERSION_3 supported) + * \param minor Minor version number (SSL_MINOR_VERSION_0, + * SSL_MINOR_VERSION_1 and SSL_MINOR_VERSION_2, + * SSL_MINOR_VERSION_3 supported) + */ +void ssl_set_max_version( ssl_context *ssl, int major, int minor ); + + +/** + * \brief Set the minimum accepted SSL/TLS protocol version + * (Default: SSL_MAJOR_VERSION_3, SSL_MINOR_VERSION_0) + * + * \param ssl SSL context + * \param major Major version number (only SSL_MAJOR_VERSION_3 supported) + * \param minor Minor version number (SSL_MINOR_VERSION_0, + * SSL_MINOR_VERSION_1 and SSL_MINOR_VERSION_2, + * SSL_MINOR_VERSION_3 supported) + */ +void ssl_set_min_version( ssl_context *ssl, int major, int minor ); + +/** + * \brief Enable / Disable renegotiation support for connection when + * initiated by peer + * (Default: SSL_RENEGOTIATION_DISABLED) + * + * Note: A server with support enabled is more vulnerable for a + * resource DoS by a malicious client. You should enable this on + * a client to enable server-initiated renegotiation. + * + * \param ssl SSL context + * \param renegotiation Enable or disable (SSL_RENEGOTIATION_ENABLED or + * SSL_RENEGOTIATION_DISABLED) + */ +void ssl_set_renegotiation( ssl_context *ssl, int renegotiation ); + +/** + * \brief Prevent or allow legacy renegotiation. + * (Default: SSL_LEGACY_NO_RENEGOTIATION) + * + * SSL_LEGACY_NO_RENEGOTIATION allows connections to + * be established even if the peer does not support + * secure renegotiation, but does not allow renegotiation + * to take place if not secure. + * (Interoperable and secure option) + * + * SSL_LEGACY_ALLOW_RENEGOTIATION allows renegotiations + * with non-upgraded peers. Allowing legacy renegotiation + * makes the connection vulnerable to specific man in the + * middle attacks. (See RFC 5746) + * (Most interoperable and least secure option) + * + * SSL_LEGACY_BREAK_HANDSHAKE breaks off connections + * if peer does not support secure renegotiation. Results + * in interoperability issues with non-upgraded peers + * that do not support renegotiation altogether. + * (Most secure option, interoperability issues) + * + * \param ssl SSL context + * \param allow_legacy Prevent or allow (SSL_NO_LEGACY_RENEGOTIATION, + * SSL_ALLOW_LEGACY_RENEGOTIATION or + * SSL_LEGACY_BREAK_HANDSHAKE) + */ +void ssl_legacy_renegotiation( ssl_context *ssl, int allow_legacy ); + +/** + * \brief Return the number of data bytes available to read + * + * \param ssl SSL context + * + * \return how many bytes are available in the read buffer + */ +size_t ssl_get_bytes_avail( const ssl_context *ssl ); + +/** + * \brief Return the result of the certificate verification + * + * \param ssl SSL context + * + * \return 0 if successful, or a combination of: + * BADCERT_EXPIRED + * BADCERT_REVOKED + * BADCERT_CN_MISMATCH + * BADCERT_NOT_TRUSTED + */ +int ssl_get_verify_result( const ssl_context *ssl ); + +/** + * \brief Return the name of the current ciphersuite + * + * \param ssl SSL context + * + * \return a string containing the ciphersuite name + */ +const char *ssl_get_ciphersuite( const ssl_context *ssl ); + +/** + * \brief Return the current SSL version (SSLv3/TLSv1/etc) + * + * \param ssl SSL context + * + * \return a string containing the SSL version + */ +const char *ssl_get_version( const ssl_context *ssl ); + +/** + * \brief Return the peer certificate from the current connection + * + * Note: Can be NULL in case no certificate was sent during + * the handshake. Different calls for the same connection can + * return the same or different pointers for the same + * certificate and even a different certificate altogether. + * The peer cert CAN change in a single connection if + * renegotiation is performed. + * + * \param ssl SSL context + * + * \return the current peer certificate + */ +const x509_cert *ssl_get_peer_cert( const ssl_context *ssl ); + +/** + * \brief Perform the SSL handshake + * + * \param ssl SSL context + * + * \return 0 if successful, POLARSSL_ERR_NET_WANT_READ, + * POLARSSL_ERR_NET_WANT_WRITE, or a specific SSL error code. + */ +int ssl_handshake( ssl_context *ssl ); + +/** + * \brief Perform a single step of the SSL handshake + * + * Note: the state of the context (ssl->state) will be at + * the following state after execution of this function. + * Do not call this function if state is SSL_HANDSHAKE_OVER. + * + * \param ssl SSL context + * + * \return 0 if successful, POLARSSL_ERR_NET_WANT_READ, + * POLARSSL_ERR_NET_WANT_WRITE, or a specific SSL error code. + */ +int ssl_handshake_step( ssl_context *ssl ); + +/** + * \brief Perform an SSL renegotiation on the running connection + * + * \param ssl SSL context + * + * \return 0 if succesful, or any ssl_handshake() return value. + */ +int ssl_renegotiate( ssl_context *ssl ); + +/** + * \brief Read at most 'len' application data bytes + * + * \param ssl SSL context + * \param buf buffer that will hold the data + * \param len how many bytes must be read + * + * \return This function returns the number of bytes read, 0 for EOF, + * or a negative error code. + */ +int ssl_read( ssl_context *ssl, unsigned char *buf, size_t len ); + +/** + * \brief Write exactly 'len' application data bytes + * + * \param ssl SSL context + * \param buf buffer holding the data + * \param len how many bytes must be written + * + * \return This function returns the number of bytes written, + * or a negative error code. + * + * \note When this function returns POLARSSL_ERR_NET_WANT_WRITE, + * it must be called later with the *same* arguments, + * until it returns a positive value. + */ +int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len ); + +/** + * \brief Send an alert message + * + * \param ssl SSL context + * \param level The alert level of the message + * (SSL_ALERT_LEVEL_WARNING or SSL_ALERT_LEVEL_FATAL) + * \param message The alert message (SSL_ALERT_MSG_*) + * + * \return 0 if successful, or a specific SSL error code. + */ +int ssl_send_alert_message( ssl_context *ssl, + unsigned char level, + unsigned char message ); +/** + * \brief Notify the peer that the connection is being closed + * + * \param ssl SSL context + */ +int ssl_close_notify( ssl_context *ssl ); + +/** + * \brief Free referenced items in an SSL context and clear memory + * + * \param ssl SSL context + */ +void ssl_free( ssl_context *ssl ); + +/** + * \brief Free referenced items in an SSL session including the + * peer certificate and clear memory + * + * \param session SSL session + */ +void ssl_session_free( ssl_session *session ); + +/** + * \brief Free referenced items in an SSL transform context and clear + * memory + * + * \param transform SSL transform context + */ +void ssl_transform_free( ssl_transform *transform ); + +/** + * \brief Free referenced items in an SSL handshake context and clear + * memory + * + * \param handshake SSL handshake context + */ +void ssl_handshake_free( ssl_handshake_params *handshake ); + +/* + * Internal functions (do not call directly) + */ +int ssl_handshake_client_step( ssl_context *ssl ); +int ssl_handshake_server_step( ssl_context *ssl ); +void ssl_handshake_wrapup( ssl_context *ssl ); + +int ssl_send_fatal_handshake_failure( ssl_context *ssl ); + +int ssl_derive_keys( ssl_context *ssl ); + +int ssl_read_record( ssl_context *ssl ); +/** + * \return 0 if successful, POLARSSL_ERR_SSL_CONN_EOF on EOF or + * another negative error code. + */ +int ssl_fetch_input( ssl_context *ssl, size_t nb_want ); + +int ssl_write_record( ssl_context *ssl ); +int ssl_flush_output( ssl_context *ssl ); + +int ssl_parse_certificate( ssl_context *ssl ); +int ssl_write_certificate( ssl_context *ssl ); + +int ssl_parse_change_cipher_spec( ssl_context *ssl ); +int ssl_write_change_cipher_spec( ssl_context *ssl ); + +int ssl_parse_finished( ssl_context *ssl ); +int ssl_write_finished( ssl_context *ssl ); + +void ssl_optimize_checksum( ssl_context *ssl, int ciphersuite ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl.h */ diff --git a/src/libpolarssl/ssl_cache.c b/src/libpolarssl/ssl_cache.c new file mode 100644 index 0000000..5ae0fd9 --- /dev/null +++ b/src/libpolarssl/ssl_cache.c @@ -0,0 +1,221 @@ +/* + * SSL session cache implementation + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * These session callbacks use a simple chained list + * to store and retrieve the session information. + */ + +#include "config.h" + +#if defined(POLARSSL_SSL_CACHE_C) + +#include "ssl_cache.h" + +#include + +void ssl_cache_init( ssl_cache_context *cache ) +{ + memset( cache, 0, sizeof( ssl_cache_context ) ); + + cache->timeout = SSL_CACHE_DEFAULT_TIMEOUT; + cache->max_entries = SSL_CACHE_DEFAULT_MAX_ENTRIES; +} + +int ssl_cache_get( void *data, ssl_session *session ) +{ + time_t t = time( NULL ); + ssl_cache_context *cache = (ssl_cache_context *) data; + ssl_cache_entry *cur, *entry; + + cur = cache->chain; + entry = NULL; + + while( cur != NULL ) + { + entry = cur; + cur = cur->next; + + if( cache->timeout != 0 && + (int) ( t - entry->timestamp ) > cache->timeout ) + continue; + + if( session->ciphersuite != entry->session.ciphersuite || + session->compression != entry->session.compression || + session->length != entry->session.length ) + continue; + + if( memcmp( session->id, entry->session.id, + entry->session.length ) != 0 ) + continue; + + memcpy( session->master, entry->session.master, 48 ); + + /* + * Restore peer certificate (without rest of the original chain) + */ + if( entry->peer_cert.p != NULL ) + { + session->peer_cert = (x509_cert *) malloc( sizeof(x509_cert) ); + if( session->peer_cert == NULL ) + return( 1 ); + + memset( session->peer_cert, 0, sizeof(x509_cert) ); + if( x509parse_crt( session->peer_cert, entry->peer_cert.p, + entry->peer_cert.len ) != 0 ) + { + free( session->peer_cert ); + session->peer_cert = NULL; + return( 1 ); + } + } + + return( 0 ); + } + + return( 1 ); +} + +int ssl_cache_set( void *data, const ssl_session *session ) +{ + time_t t = time( NULL ), oldest = 0; + ssl_cache_context *cache = (ssl_cache_context *) data; + ssl_cache_entry *cur, *prv, *old = NULL; + int count = 0; + + cur = cache->chain; + prv = NULL; + + while( cur != NULL ) + { + count++; + + if( cache->timeout != 0 && + (int) ( t - cur->timestamp ) > cache->timeout ) + { + cur->timestamp = t; + break; /* expired, reuse this slot, update timestamp */ + } + + if( memcmp( session->id, cur->session.id, cur->session.length ) == 0 ) + break; /* client reconnected, keep timestamp for session id */ + + if( oldest == 0 || cur->timestamp < oldest ) + { + oldest = cur->timestamp; + old = cur; + } + + prv = cur; + cur = cur->next; + } + + if( cur == NULL ) + { + /* + * Reuse oldest entry if max_entries reached + */ + if( old != NULL && count >= cache->max_entries ) + { + cur = old; + memset( &cur->session, 0, sizeof(ssl_session) ); + if( cur->peer_cert.p != NULL ) + { + free( cur->peer_cert.p ); + memset( &cur->peer_cert, 0, sizeof(x509_buf) ); + } + } + else + { + cur = (ssl_cache_entry *) malloc( sizeof(ssl_cache_entry) ); + if( cur == NULL ) + return( 1 ); + + memset( cur, 0, sizeof(ssl_cache_entry) ); + + if( prv == NULL ) + cache->chain = cur; + else + prv->next = cur; + } + + cur->timestamp = t; + } + + memcpy( &cur->session, session, sizeof( ssl_session ) ); + + /* + * Store peer certificate + */ + if( session->peer_cert != NULL ) + { + cur->peer_cert.p = (unsigned char *) malloc( session->peer_cert->raw.len ); + if( cur->peer_cert.p == NULL ) + return( 1 ); + + memcpy( cur->peer_cert.p, session->peer_cert->raw.p, + session->peer_cert->raw.len ); + cur->peer_cert.len = session->peer_cert->raw.len; + + cur->session.peer_cert = NULL; + } + + return( 0 ); +} + +void ssl_cache_set_timeout( ssl_cache_context *cache, int timeout ) +{ + if( timeout < 0 ) timeout = 0; + + cache->timeout = timeout; +} + +void ssl_cache_set_max_entries( ssl_cache_context *cache, int max ) +{ + if( max < 0 ) max = 0; + + cache->max_entries = max; +} + +void ssl_cache_free( ssl_cache_context *cache ) +{ + ssl_cache_entry *cur, *prv; + + cur = cache->chain; + + while( cur != NULL ) + { + prv = cur; + cur = cur->next; + + ssl_session_free( &prv->session ); + + if( prv->peer_cert.p != NULL ) + free( prv->peer_cert.p ); + + free( prv ); + } +} + +#endif /* POLARSSL_SSL_CACHE_C */ diff --git a/src/libpolarssl/ssl_cache.h b/src/libpolarssl/ssl_cache.h new file mode 100644 index 0000000..8d66b5c --- /dev/null +++ b/src/libpolarssl/ssl_cache.h @@ -0,0 +1,119 @@ +/** + * \file ssl_cache.h + * + * \brief SSL session cache implementation + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_SSL_CACHE_H +#define POLARSSL_SSL_CACHE_H + +#include "ssl.h" + +#if !defined(POLARSSL_CONFIG_OPTIONS) +#define SSL_CACHE_DEFAULT_TIMEOUT 86400 /*!< 1 day */ +#define SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /*!< Maximum entries in cache */ +#endif /* !POLARSSL_CONFIG_OPTIONS */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _ssl_cache_context ssl_cache_context; +typedef struct _ssl_cache_entry ssl_cache_entry; + +/** + * \brief This structure is used for storing cache entries + */ +struct _ssl_cache_entry +{ + time_t timestamp; /*!< entry timestamp */ + ssl_session session; /*!< entry session */ + x509_buf peer_cert; /*!< entry peer_cert */ + ssl_cache_entry *next; /*!< chain pointer */ +}; + +/** + * \brief Cache context + */ +struct _ssl_cache_context +{ + ssl_cache_entry *chain; /*!< start of the chain */ + int timeout; /*!< cache entry timeout */ + int max_entries; /*!< maximum entries */ +}; + +/** + * \brief Initialize an SSL cache context + * + * \param cache SSL cache context + */ +void ssl_cache_init( ssl_cache_context *cache ); + +/** + * \brief Cache get callback implementation + * + * \param data SSL cache context + * \param session session to retrieve entry for + */ +int ssl_cache_get( void *data, ssl_session *session ); + +/** + * \brief Cache set callback implementation + * + * \param data SSL cache context + * \param session session to store entry for + */ +int ssl_cache_set( void *data, const ssl_session *session ); + +/** + * \brief Set the cache timeout + * (Default: SSL_CACHE_DEFAULT_TIMEOUT (1 day)) + * + * A timeout of 0 indicates no timeout. + * + * \param cache SSL cache context + * \param timeout cache entry timeout + */ +void ssl_cache_set_timeout( ssl_cache_context *cache, int timeout ); + +/** + * \brief Set the cache timeout + * (Default: SSL_CACHE_DEFAULT_MAX_ENTRIES (50)) + * + * \param cache SSL cache context + * \param max cache entry maximum + */ +void ssl_cache_set_max_entries( ssl_cache_context *cache, int max ); + +/** + * \brief Free referenced items in a cache context and clear memory + * + * \param cache SSL cache context + */ +void ssl_cache_free( ssl_cache_context *cache ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_cache.h */ diff --git a/src/libpolarssl/ssl_cli.c b/src/libpolarssl/ssl_cli.c new file mode 100644 index 0000000..8dff9a4 --- /dev/null +++ b/src/libpolarssl/ssl_cli.c @@ -0,0 +1,1386 @@ +/* + * SSLv3/TLSv1 client-side functions + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_SSL_CLI_C) + +#include "debug.h" +#include "ssl.h" + +#include +#include +#include + +#if defined(POLARSSL_SHA4_C) +#include "sha4.h" +#endif + +static int ssl_write_client_hello( ssl_context *ssl ) +{ + int ret; + size_t i, n, ext_len = 0; + unsigned char *buf; + unsigned char *p; + time_t t; + unsigned char sig_alg_list[20]; + size_t sig_alg_len = 0; + + SSL_DEBUG_MSG( 2, ( "=> write client hello" ) ); + + if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) + { + ssl->major_ver = ssl->min_major_ver; + ssl->minor_ver = ssl->min_minor_ver; + } + + if( ssl->max_major_ver == 0 && ssl->max_minor_ver == 0 ) + { + ssl->max_major_ver = SSL_MAJOR_VERSION_3; + ssl->max_minor_ver = SSL_MINOR_VERSION_3; + } + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 highest version supported + * 6 . 9 current UNIX time + * 10 . 37 random bytes + */ + buf = ssl->out_msg; + p = buf + 4; + + *p++ = (unsigned char) ssl->max_major_ver; + *p++ = (unsigned char) ssl->max_minor_ver; + + SSL_DEBUG_MSG( 3, ( "client hello, max version: [%d:%d]", + buf[4], buf[5] ) ); + + t = time( NULL ); + *p++ = (unsigned char)( t >> 24 ); + *p++ = (unsigned char)( t >> 16 ); + *p++ = (unsigned char)( t >> 8 ); + *p++ = (unsigned char)( t ); + + SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) ); + + if( ( ret = ssl->f_rng( ssl->p_rng, p, 28 ) ) != 0 ) + return( ret ); + + p += 28; + + memcpy( ssl->handshake->randbytes, buf + 6, 32 ); + + SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 6, 32 ); + + /* + * 38 . 38 session id length + * 39 . 39+n session id + * 40+n . 41+n ciphersuitelist length + * 42+n . .. ciphersuitelist + * .. . .. compression methods length + * .. . .. compression methods + * .. . .. extensions length + * .. . .. extensions + */ + n = ssl->session_negotiate->length; + + if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE || n < 16 || n > 32 || + ssl->handshake->resume == 0 ) + n = 0; + + *p++ = (unsigned char) n; + + for( i = 0; i < n; i++ ) + *p++ = ssl->session_negotiate->id[i]; + + SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) ); + SSL_DEBUG_BUF( 3, "client hello, session id", buf + 39, n ); + + for( n = 0; ssl->ciphersuites[ssl->minor_ver][n] != 0; n++ ); + if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) n++; + *p++ = (unsigned char)( n >> 7 ); + *p++ = (unsigned char)( n << 1 ); + + /* + * Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ + if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) + { + *p++ = (unsigned char)( SSL_EMPTY_RENEGOTIATION_INFO >> 8 ); + *p++ = (unsigned char)( SSL_EMPTY_RENEGOTIATION_INFO ); + n--; + } + + SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphersuites", n ) ); + + for( i = 0; i < n; i++ ) + { + SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %2d", + ssl->ciphersuites[ssl->minor_ver][i] ) ); + + *p++ = (unsigned char)( ssl->ciphersuites[ssl->minor_ver][i] >> 8 ); + *p++ = (unsigned char)( ssl->ciphersuites[ssl->minor_ver][i] ); + } + +#if defined(POLARSSL_ZLIB_SUPPORT) + SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 2 ) ); + SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d %d", + SSL_COMPRESS_DEFLATE, SSL_COMPRESS_NULL ) ); + + *p++ = 2; + *p++ = SSL_COMPRESS_DEFLATE; + *p++ = SSL_COMPRESS_NULL; +#else + SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 1 ) ); + SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d", SSL_COMPRESS_NULL ) ); + + *p++ = 1; + *p++ = SSL_COMPRESS_NULL; +#endif + + if ( ssl->hostname != NULL ) + { + SSL_DEBUG_MSG( 3, ( "client hello, prepping for server name extension: %s", + ssl->hostname ) ); + + ext_len += ssl->hostname_len + 9; + } + + if( ssl->renegotiation == SSL_RENEGOTIATION ) + { + SSL_DEBUG_MSG( 3, ( "client hello, prepping for renegotiation extension" ) ); + ext_len += 5 + ssl->verify_data_len; + } + + /* + * Prepare signature_algorithms extension (TLS 1.2) + */ + if( ssl->max_minor_ver == SSL_MINOR_VERSION_3 ) + { +#if defined(POLARSSL_SHA4_C) + sig_alg_list[sig_alg_len++] = SSL_HASH_SHA512; + sig_alg_list[sig_alg_len++] = SSL_SIG_RSA; + sig_alg_list[sig_alg_len++] = SSL_HASH_SHA384; + sig_alg_list[sig_alg_len++] = SSL_SIG_RSA; +#endif +#if defined(POLARSSL_SHA2_C) + sig_alg_list[sig_alg_len++] = SSL_HASH_SHA256; + sig_alg_list[sig_alg_len++] = SSL_SIG_RSA; + sig_alg_list[sig_alg_len++] = SSL_HASH_SHA224; + sig_alg_list[sig_alg_len++] = SSL_SIG_RSA; +#endif +#if defined(POLARSSL_SHA1_C) + sig_alg_list[sig_alg_len++] = SSL_HASH_SHA1; + sig_alg_list[sig_alg_len++] = SSL_SIG_RSA; +#endif +#if defined(POLARSSL_MD5_C) + sig_alg_list[sig_alg_len++] = SSL_HASH_MD5; + sig_alg_list[sig_alg_len++] = SSL_SIG_RSA; +#endif + ext_len += 6 + sig_alg_len; + } + + SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d", + ext_len ) ); + + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len ) & 0xFF ); + + if ( ssl->hostname != NULL ) + { + /* + * struct { + * NameType name_type; + * select (name_type) { + * case host_name: HostName; + * } name; + * } ServerName; + * + * enum { + * host_name(0), (255) + * } NameType; + * + * opaque HostName<1..2^16-1>; + * + * struct { + * ServerName server_name_list<1..2^16-1> + * } ServerNameList; + */ + SSL_DEBUG_MSG( 3, ( "client hello, adding server name extension: %s", + ssl->hostname ) ); + + *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME ) & 0xFF ); + + *p++ = (unsigned char)( ( (ssl->hostname_len + 5) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( (ssl->hostname_len + 5) ) & 0xFF ); + + *p++ = (unsigned char)( ( (ssl->hostname_len + 3) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( (ssl->hostname_len + 3) ) & 0xFF ); + + *p++ = (unsigned char)( ( TLS_EXT_SERVERNAME_HOSTNAME ) & 0xFF ); + *p++ = (unsigned char)( ( ssl->hostname_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ssl->hostname_len ) & 0xFF ); + + memcpy( p, ssl->hostname, ssl->hostname_len ); + p += ssl->hostname_len; + } + + if( ssl->renegotiation == SSL_RENEGOTIATION ) + { + /* + * Secure renegotiation + */ + SSL_DEBUG_MSG( 3, ( "client hello, renegotiation info extension" ) ); + + *p++ = (unsigned char)( ( TLS_EXT_RENEGOTIATION_INFO >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( TLS_EXT_RENEGOTIATION_INFO ) & 0xFF ); + + *p++ = 0x00; + *p++ = ( ssl->verify_data_len + 1 ) & 0xFF; + *p++ = ssl->verify_data_len & 0xFF; + + memcpy( p, ssl->own_verify_data, ssl->verify_data_len ); + p += ssl->verify_data_len; + } + + if( ssl->max_minor_ver == SSL_MINOR_VERSION_3 ) + { + /* + * enum { + * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), + * sha512(6), (255) + * } HashAlgorithm; + * + * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } + * SignatureAlgorithm; + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + * + * SignatureAndHashAlgorithm + * supported_signature_algorithms<2..2^16-2>; + */ + SSL_DEBUG_MSG( 3, ( "client hello, adding signature_algorithms extension" ) ); + + *p++ = (unsigned char)( ( TLS_EXT_SIG_ALG >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( TLS_EXT_SIG_ALG ) & 0xFF ); + + *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( sig_alg_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( sig_alg_len ) & 0xFF ); + + memcpy( p, sig_alg_list, sig_alg_len ); + + p += sig_alg_len; + } + + ssl->out_msglen = p - buf; + ssl->out_msgtype = SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = SSL_HS_CLIENT_HELLO; + + ssl->state++; + + if( ( ret = ssl_write_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + + SSL_DEBUG_MSG( 2, ( "<= write client hello" ) ); + + return( 0 ); +} + +static int ssl_parse_renegotiation_info( ssl_context *ssl, + unsigned char *buf, + size_t len ) +{ + int ret; + + if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) + { + if( len != 1 || buf[0] != 0x0 ) + { + SSL_DEBUG_MSG( 1, ( "non-zero length renegotiated connection field" ) ); + + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION; + } + else + { + if( len != 1 + ssl->verify_data_len * 2 || + buf[0] != ssl->verify_data_len * 2 || + memcmp( buf + 1, ssl->own_verify_data, ssl->verify_data_len ) != 0 || + memcmp( buf + 1 + ssl->verify_data_len, + ssl->peer_verify_data, ssl->verify_data_len ) != 0 ) + { + SSL_DEBUG_MSG( 1, ( "non-matching renegotiated connection field" ) ); + + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + + return( 0 ); +} + +static int ssl_parse_server_hello( ssl_context *ssl ) +{ +#if defined(POLARSSL_DEBUG_C) + time_t t; +#endif + int ret, i, comp; + size_t n; + size_t ext_len = 0; + unsigned char *buf, *ext; + int renegotiation_info_seen = 0; + int handshake_failure = 0; + + SSL_DEBUG_MSG( 2, ( "=> parse server hello" ) ); + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 protocol version + * 6 . 9 UNIX time() + * 10 . 37 random bytes + */ + buf = ssl->in_msg; + + if( ( ret = ssl_read_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != SSL_MSG_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [%d:%d]", + buf[4], buf[5] ) ); + + if( ssl->in_hslen < 42 || + buf[0] != SSL_HS_SERVER_HELLO || + buf[4] != SSL_MAJOR_VERSION_3 ) + { + SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( buf[5] > ssl->max_minor_ver ) + { + SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ssl->minor_ver = buf[5]; + + if( ssl->minor_ver < ssl->min_minor_ver ) + { + SSL_DEBUG_MSG( 1, ( "server only supports ssl smaller than minimum" + " [%d:%d] < [%d:%d]", ssl->major_ver, ssl->minor_ver, + buf[4], buf[5] ) ); + + ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL, + SSL_ALERT_MSG_PROTOCOL_VERSION ); + + return( POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + +#if defined(POLARSSL_DEBUG_C) + t = ( (time_t) buf[6] << 24 ) + | ( (time_t) buf[7] << 16 ) + | ( (time_t) buf[8] << 8 ) + | ( (time_t) buf[9] ); +#endif + + memcpy( ssl->handshake->randbytes + 32, buf + 6, 32 ); + + n = buf[38]; + + SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) ); + SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 6, 32 ); + + if( n > 32 ) + { + SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* + * 38 . 38 session id length + * 39 . 38+n session id + * 39+n . 40+n chosen ciphersuite + * 41+n . 41+n chosen compression alg. + * 42+n . 43+n extensions length + * 44+n . 44+n+m extensions + */ + if( ssl->in_hslen > 42 + n ) + { + ext_len = ( ( buf[42 + n] << 8 ) + | ( buf[43 + n] ) ); + + if( ( ext_len > 0 && ext_len < 4 ) || + ssl->in_hslen != 44 + n + ext_len ) + { + SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + + i = ( buf[39 + n] << 8 ) | buf[40 + n]; + comp = buf[41 + n]; + + /* + * Initialize update checksum functions + */ + ssl_optimize_checksum( ssl, i ); + + SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) ); + SSL_DEBUG_BUF( 3, "server hello, session id", buf + 39, n ); + + /* + * Check if the session can be resumed + */ + if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE || + ssl->handshake->resume == 0 || n == 0 || + ssl->session_negotiate->ciphersuite != i || + ssl->session_negotiate->compression != comp || + ssl->session_negotiate->length != n || + memcmp( ssl->session_negotiate->id, buf + 39, n ) != 0 ) + { + ssl->state++; + ssl->handshake->resume = 0; + ssl->session_negotiate->start = time( NULL ); + ssl->session_negotiate->ciphersuite = i; + ssl->session_negotiate->compression = comp; + ssl->session_negotiate->length = n; + memcpy( ssl->session_negotiate->id, buf + 39, n ); + } + else + { + ssl->state = SSL_SERVER_CHANGE_CIPHER_SPEC; + + if( ( ret = ssl_derive_keys( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_derive_keys", ret ); + return( ret ); + } + } + + SSL_DEBUG_MSG( 3, ( "%s session has been resumed", + ssl->handshake->resume ? "a" : "no" ) ); + + SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %d", i ) ); + SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", buf[41 + n] ) ); + + i = 0; + while( 1 ) + { + if( ssl->ciphersuites[ssl->minor_ver][i] == 0 ) + { + SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( ssl->ciphersuites[ssl->minor_ver][i++] == ssl->session_negotiate->ciphersuite ) + break; + } + + if( comp != SSL_COMPRESS_NULL +#if defined(POLARSSL_ZLIB_SUPPORT) + && comp != SSL_COMPRESS_DEFLATE +#endif + ) + { + SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + ssl->session_negotiate->compression = comp; + + ext = buf + 44 + n; + + while( ext_len ) + { + unsigned int ext_id = ( ( ext[0] << 8 ) + | ( ext[1] ) ); + unsigned int ext_size = ( ( ext[2] << 8 ) + | ( ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + switch( ext_id ) + { + case TLS_EXT_RENEGOTIATION_INFO: + SSL_DEBUG_MSG( 3, ( "found renegotiation extension" ) ); + renegotiation_info_seen = 1; + + if( ( ret = ssl_parse_renegotiation_info( ssl, ext + 4, ext_size ) ) != 0 ) + return( ret ); + + break; + + default: + SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", + ext_id ) ); + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + + /* + * Renegotiation security checks + */ + if( ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && + ssl->allow_legacy_renegotiation == SSL_LEGACY_BREAK_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); + handshake_failure = 1; + } + else if( ssl->renegotiation == SSL_RENEGOTIATION && + ssl->secure_renegotiation == SSL_SECURE_RENEGOTIATION && + renegotiation_info_seen == 0 ) + { + SSL_DEBUG_MSG( 1, ( "renegotiation_info extension missing (secure)" ) ); + handshake_failure = 1; + } + else if( ssl->renegotiation == SSL_RENEGOTIATION && + ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && + ssl->allow_legacy_renegotiation == SSL_LEGACY_NO_RENEGOTIATION ) + { + SSL_DEBUG_MSG( 1, ( "legacy renegotiation not allowed" ) ); + handshake_failure = 1; + } + else if( ssl->renegotiation == SSL_RENEGOTIATION && + ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && + renegotiation_info_seen == 1 ) + { + SSL_DEBUG_MSG( 1, ( "renegotiation_info extension present (legacy)" ) ); + handshake_failure = 1; + } + + if( handshake_failure == 1 ) + { + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + SSL_DEBUG_MSG( 2, ( "<= parse server hello" ) ); + + return( 0 ); +} + +static int ssl_parse_server_key_exchange( ssl_context *ssl ) +{ +#if defined(POLARSSL_DHM_C) + int ret; + size_t n; + unsigned char *p, *end; + unsigned char hash[64]; + md5_context md5; + sha1_context sha1; + int hash_id = SIG_RSA_RAW; + unsigned int hashlen = 0; +#endif + + SSL_DEBUG_MSG( 2, ( "=> parse server key exchange" ) ); + + if( ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_DES_CBC_SHA && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ) + { + SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) ); + ssl->state++; + return( 0 ); + } + +#if !defined(POLARSSL_DHM_C) + SSL_DEBUG_MSG( 1, ( "support for dhm in not available" ) ); + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); +#else + if( ( ret = ssl_read_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != SSL_MSG_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->in_msg[0] != SSL_HS_SERVER_KEY_EXCHANGE ) + { + SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + SSL_DEBUG_BUF( 3, "server key exchange", ssl->in_msg + 4, ssl->in_hslen - 4 ); + + /* + * Ephemeral DH parameters: + * + * struct { + * opaque dh_p<1..2^16-1>; + * opaque dh_g<1..2^16-1>; + * opaque dh_Ys<1..2^16-1>; + * } ServerDHParams; + */ + p = ssl->in_msg + 4; + end = ssl->in_msg + ssl->in_hslen; + + if( ( ret = dhm_read_params( &ssl->handshake->dhm_ctx, &p, end ) ) != 0 ) + { + SSL_DEBUG_MSG( 2, ( "DHM Read Params returned -0x%x", -ret ) ); + SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + if( ssl->minor_ver == SSL_MINOR_VERSION_3 ) + { + if( p[1] != SSL_SIG_RSA ) + { + SSL_DEBUG_MSG( 2, ( "server used unsupported SignatureAlgorithm %d", p[1] ) ); + SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + switch( p[0] ) + { +#if defined(POLARSSL_MD5_C) + case SSL_HASH_MD5: + hash_id = SIG_RSA_MD5; + break; +#endif +#if defined(POLARSSL_SHA1_C) + case SSL_HASH_SHA1: + hash_id = SIG_RSA_SHA1; + break; +#endif +#if defined(POLARSSL_SHA2_C) + case SSL_HASH_SHA224: + hash_id = SIG_RSA_SHA224; + break; + case SSL_HASH_SHA256: + hash_id = SIG_RSA_SHA256; + break; +#endif +#if defined(POLARSSL_SHA4_C) + case SSL_HASH_SHA384: + hash_id = SIG_RSA_SHA384; + break; + case SSL_HASH_SHA512: + hash_id = SIG_RSA_SHA512; + break; +#endif + default: + SSL_DEBUG_MSG( 2, ( "Server used unsupported HashAlgorithm %d", p[0] ) ); + SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + SSL_DEBUG_MSG( 2, ( "Server used SignatureAlgorithm %d", p[1] ) ); + SSL_DEBUG_MSG( 2, ( "Server used HashAlgorithm %d", p[0] ) ); + p += 2; + } + + n = ( p[0] << 8 ) | p[1]; + p += 2; + + if( end != p + n ) + { + SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + if( (unsigned int)( end - p ) != + ssl->session_negotiate->peer_cert->rsa.len ) + { + SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + if( ssl->handshake->dhm_ctx.len < 64 || ssl->handshake->dhm_ctx.len > 512 ) + { + SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P ); + SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->handshake->dhm_ctx.G ); + SSL_DEBUG_MPI( 3, "DHM: GY", &ssl->handshake->dhm_ctx.GY ); + + if( ssl->minor_ver != SSL_MINOR_VERSION_3 ) + { + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(ClientHello.random + ServerHello.random + * + ServerParams); + * sha_hash + * SHA(ClientHello.random + ServerHello.random + * + ServerParams); + */ + n = ssl->in_hslen - ( end - p ) - 6; + + md5_starts( &md5 ); + md5_update( &md5, ssl->handshake->randbytes, 64 ); + md5_update( &md5, ssl->in_msg + 4, n ); + md5_finish( &md5, hash ); + + sha1_starts( &sha1 ); + sha1_update( &sha1, ssl->handshake->randbytes, 64 ); + sha1_update( &sha1, ssl->in_msg + 4, n ); + sha1_finish( &sha1, hash + 16 ); + + hash_id = SIG_RSA_RAW; + hashlen = 36; + } + else + { + sha2_context sha2; +#if defined(POLARSSL_SHA4_C) + sha4_context sha4; +#endif + + n = ssl->in_hslen - ( end - p ) - 8; + + /* + * digitally-signed struct { + * opaque client_random[32]; + * opaque server_random[32]; + * ServerDHParams params; + * }; + */ + switch( hash_id ) + { +#if defined(POLARSSL_MD5_C) + case SIG_RSA_MD5: + md5_starts( &md5 ); + md5_update( &md5, ssl->handshake->randbytes, 64 ); + md5_update( &md5, ssl->in_msg + 4, n ); + md5_finish( &md5, hash ); + hashlen = 16; + break; +#endif +#if defined(POLARSSL_SHA1_C) + case SIG_RSA_SHA1: + sha1_starts( &sha1 ); + sha1_update( &sha1, ssl->handshake->randbytes, 64 ); + sha1_update( &sha1, ssl->in_msg + 4, n ); + sha1_finish( &sha1, hash ); + hashlen = 20; + break; +#endif +#if defined(POLARSSL_SHA2_C) + case SIG_RSA_SHA224: + sha2_starts( &sha2, 1 ); + sha2_update( &sha2, ssl->handshake->randbytes, 64 ); + sha2_update( &sha2, ssl->in_msg + 4, n ); + sha2_finish( &sha2, hash ); + hashlen = 28; + break; + case SIG_RSA_SHA256: + sha2_starts( &sha2, 0 ); + sha2_update( &sha2, ssl->handshake->randbytes, 64 ); + sha2_update( &sha2, ssl->in_msg + 4, n ); + sha2_finish( &sha2, hash ); + hashlen = 32; + break; +#endif +#if defined(POLARSSL_SHA4_C) + case SIG_RSA_SHA384: + sha4_starts( &sha4, 1 ); + sha4_update( &sha4, ssl->handshake->randbytes, 64 ); + sha4_update( &sha4, ssl->in_msg + 4, n ); + sha4_finish( &sha4, hash ); + hashlen = 48; + break; + case SIG_RSA_SHA512: + sha4_starts( &sha4, 0 ); + sha4_update( &sha4, ssl->handshake->randbytes, 64 ); + sha4_update( &sha4, ssl->in_msg + 4, n ); + sha4_finish( &sha4, hash ); + hashlen = 64; + break; +#endif + } + } + + SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen ); + + if( ( ret = rsa_pkcs1_verify( &ssl->session_negotiate->peer_cert->rsa, + RSA_PUBLIC, + hash_id, hashlen, hash, p ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "rsa_pkcs1_verify", ret ); + return( ret ); + } + + ssl->state++; + + SSL_DEBUG_MSG( 2, ( "<= parse server key exchange" ) ); + + return( 0 ); +#endif +} + +static int ssl_parse_certificate_request( ssl_context *ssl ) +{ + int ret; + unsigned char *buf, *p; + size_t n = 0, m = 0; + size_t cert_type_len = 0, sig_alg_len = 0, dn_len = 0; + + SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) ); + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 4 cert type count + * 5 .. m-1 cert types + * m .. m+1 sig alg length (TLS 1.2 only) + * m+1 .. n-1 SignatureAndHashAlgorithms (TLS 1.2 only) + * n .. n+1 length of all DNs + * n+2 .. n+3 length of DN 1 + * n+4 .. ... Distinguished Name #1 + * ... .. ... length of DN 2, etc. + */ + if( ( ret = ssl_read_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != SSL_MSG_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + ssl->client_auth = 0; + ssl->state++; + + if( ssl->in_msg[0] == SSL_HS_CERTIFICATE_REQUEST ) + ssl->client_auth++; + + SSL_DEBUG_MSG( 3, ( "got %s certificate request", + ssl->client_auth ? "a" : "no" ) ); + + if( ssl->client_auth == 0 ) + goto exit; + + // TODO: handshake_failure alert for an anonymous server to request + // client authentication + + buf = ssl->in_msg; + + // Retrieve cert types + // + cert_type_len = buf[4]; + n = cert_type_len; + + if( ssl->in_hslen < 6 + n ) + { + SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + p = buf + 5; + while( cert_type_len > 0 ) + { + if( *p == SSL_CERT_TYPE_RSA_SIGN ) + { + ssl->handshake->cert_type = SSL_CERT_TYPE_RSA_SIGN; + break; + } + + cert_type_len--; + p++; + } + + if( ssl->handshake->cert_type == 0 ) + { + SSL_DEBUG_MSG( 1, ( "no known cert_type provided" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + if( ssl->minor_ver == SSL_MINOR_VERSION_3 ) + { + sig_alg_len = ( ( buf[5 + n] << 8 ) + | ( buf[6 + n] ) ); + + p = buf + 7 + n; + m += 2; + n += sig_alg_len; + + if( ssl->in_hslen < 6 + n ) + { + SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + } + + dn_len = ( ( buf[5 + m + n] << 8 ) + | ( buf[6 + m + n] ) ); + + n += dn_len; + if( ssl->in_hslen != 7 + m + n ) + { + SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + +exit: + SSL_DEBUG_MSG( 2, ( "<= parse certificate request" ) ); + + return( 0 ); +} + +static int ssl_parse_server_hello_done( ssl_context *ssl ) +{ + int ret; + + SSL_DEBUG_MSG( 2, ( "=> parse server hello done" ) ); + + if( ssl->client_auth != 0 ) + { + if( ( ret = ssl_read_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != SSL_MSG_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) ); + return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + } + } + + if( ssl->in_hslen != 4 || + ssl->in_msg[0] != SSL_HS_SERVER_HELLO_DONE ) + { + SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO_DONE ); + } + + ssl->state++; + + SSL_DEBUG_MSG( 2, ( "<= parse server hello done" ) ); + + return( 0 ); +} + +static int ssl_write_client_key_exchange( ssl_context *ssl ) +{ + int ret; + size_t i, n; + + SSL_DEBUG_MSG( 2, ( "=> write client key exchange" ) ); + + if( ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_DES_CBC_SHA || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ) + { +#if !defined(POLARSSL_DHM_C) + SSL_DEBUG_MSG( 1, ( "support for dhm in not available" ) ); + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); +#else + /* + * DHM key exchange -- send G^X mod P + */ + n = ssl->handshake->dhm_ctx.len; + + ssl->out_msg[4] = (unsigned char)( n >> 8 ); + ssl->out_msg[5] = (unsigned char)( n ); + i = 6; + + ret = dhm_make_public( &ssl->handshake->dhm_ctx, + mpi_size( &ssl->handshake->dhm_ctx.P ), + &ssl->out_msg[i], n, + ssl->f_rng, ssl->p_rng ); + if( ret != 0 ) + { + SSL_DEBUG_RET( 1, "dhm_make_public", ret ); + return( ret ); + } + + SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X ); + SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->handshake->dhm_ctx.GX ); + + ssl->handshake->pmslen = ssl->handshake->dhm_ctx.len; + + if( ( ret = dhm_calc_secret( &ssl->handshake->dhm_ctx, + ssl->handshake->premaster, + &ssl->handshake->pmslen ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "dhm_calc_secret", ret ); + return( ret ); + } + + SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K ); +#endif + } + else + { + /* + * RSA key exchange -- send rsa_public(pkcs1 v1.5(premaster)) + */ + ssl->handshake->premaster[0] = (unsigned char) ssl->max_major_ver; + ssl->handshake->premaster[1] = (unsigned char) ssl->max_minor_ver; + ssl->handshake->pmslen = 48; + + ret = ssl->f_rng( ssl->p_rng, ssl->handshake->premaster + 2, + ssl->handshake->pmslen - 2 ); + if( ret != 0 ) + return( ret ); + + i = 4; + n = ssl->session_negotiate->peer_cert->rsa.len; + + if( ssl->minor_ver != SSL_MINOR_VERSION_0 ) + { + i += 2; + ssl->out_msg[4] = (unsigned char)( n >> 8 ); + ssl->out_msg[5] = (unsigned char)( n ); + } + + ret = rsa_pkcs1_encrypt( &ssl->session_negotiate->peer_cert->rsa, + ssl->f_rng, ssl->p_rng, + RSA_PUBLIC, + ssl->handshake->pmslen, + ssl->handshake->premaster, + ssl->out_msg + i ); + if( ret != 0 ) + { + SSL_DEBUG_RET( 1, "rsa_pkcs1_encrypt", ret ); + return( ret ); + } + } + + if( ( ret = ssl_derive_keys( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_derive_keys", ret ); + return( ret ); + } + + ssl->out_msglen = i + n; + ssl->out_msgtype = SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = SSL_HS_CLIENT_KEY_EXCHANGE; + + ssl->state++; + + if( ( ret = ssl_write_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + + SSL_DEBUG_MSG( 2, ( "<= write client key exchange" ) ); + + return( 0 ); +} + +static int ssl_write_certificate_verify( ssl_context *ssl ) +{ + int ret = 0; + size_t n = 0, offset = 0; + unsigned char hash[48]; + int hash_id = SIG_RSA_RAW; + unsigned int hashlen = 36; + + SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) ); + + if( ssl->client_auth == 0 || ssl->own_cert == NULL ) + { + SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + if( ssl->rsa_key == NULL ) + { + SSL_DEBUG_MSG( 1, ( "got no private key" ) ); + return( POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Make an RSA signature of the handshake digests + */ + ssl->handshake->calc_verify( ssl, hash ); + + if( ssl->minor_ver != SSL_MINOR_VERSION_3 ) + { + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(handshake_messages); + * + * sha_hash + * SHA(handshake_messages); + */ + hashlen = 36; + hash_id = SIG_RSA_RAW; + } + else + { + /* + * digitally-signed struct { + * opaque handshake_messages[handshake_messages_length]; + * }; + * + * Taking shortcut here. We assume that the server always allows the + * PRF Hash function and has sent it in the allowed signature + * algorithms list received in the Certificate Request message. + * + * Until we encounter a server that does not, we will take this + * shortcut. + * + * Reason: Otherwise we should have running hashes for SHA512 and SHA224 + * in order to satisfy 'weird' needs from the server side. + */ + if( ssl->session_negotiate->ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ) + { + hash_id = SIG_RSA_SHA384; + hashlen = 48; + ssl->out_msg[4] = SSL_HASH_SHA384; + ssl->out_msg[5] = SSL_SIG_RSA; + } + else + { + hash_id = SIG_RSA_SHA256; + hashlen = 32; + ssl->out_msg[4] = SSL_HASH_SHA256; + ssl->out_msg[5] = SSL_SIG_RSA; + } + + offset = 2; + } + + if ( ssl->rsa_key ) + n = ssl->rsa_key_len ( ssl->rsa_key ); + + ssl->out_msg[4 + offset] = (unsigned char)( n >> 8 ); + ssl->out_msg[5 + offset] = (unsigned char)( n ); + + if( ssl->rsa_key ) + { + ret = ssl->rsa_sign( ssl->rsa_key, ssl->f_rng, ssl->p_rng, + RSA_PRIVATE, hash_id, + hashlen, hash, ssl->out_msg + 6 + offset ); + } + + if (ret != 0) + { + SSL_DEBUG_RET( 1, "pkcs1_sign", ret ); + return( ret ); + } + + ssl->out_msglen = 6 + n + offset; + ssl->out_msgtype = SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = SSL_HS_CERTIFICATE_VERIFY; + + ssl->state++; + + if( ( ret = ssl_write_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + + SSL_DEBUG_MSG( 2, ( "<= write certificate verify" ) ); + + return( 0 ); +} + +/* + * SSL handshake -- client side -- single step + */ +int ssl_handshake_client_step( ssl_context *ssl ) +{ + int ret = 0; + + if( ssl->state == SSL_HANDSHAKE_OVER ) + return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + + SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) ); + + if( ( ret = ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + switch( ssl->state ) + { + case SSL_HELLO_REQUEST: + ssl->state = SSL_CLIENT_HELLO; + break; + + /* + * ==> ClientHello + */ + case SSL_CLIENT_HELLO: + ret = ssl_write_client_hello( ssl ); + break; + + /* + * <== ServerHello + * Certificate + * ( ServerKeyExchange ) + * ( CertificateRequest ) + * ServerHelloDone + */ + case SSL_SERVER_HELLO: + ret = ssl_parse_server_hello( ssl ); + break; + + case SSL_SERVER_CERTIFICATE: + ret = ssl_parse_certificate( ssl ); + break; + + case SSL_SERVER_KEY_EXCHANGE: + ret = ssl_parse_server_key_exchange( ssl ); + break; + + case SSL_CERTIFICATE_REQUEST: + ret = ssl_parse_certificate_request( ssl ); + break; + + case SSL_SERVER_HELLO_DONE: + ret = ssl_parse_server_hello_done( ssl ); + break; + + /* + * ==> ( Certificate/Alert ) + * ClientKeyExchange + * ( CertificateVerify ) + * ChangeCipherSpec + * Finished + */ + case SSL_CLIENT_CERTIFICATE: + ret = ssl_write_certificate( ssl ); + break; + + case SSL_CLIENT_KEY_EXCHANGE: + ret = ssl_write_client_key_exchange( ssl ); + break; + + case SSL_CERTIFICATE_VERIFY: + ret = ssl_write_certificate_verify( ssl ); + break; + + case SSL_CLIENT_CHANGE_CIPHER_SPEC: + ret = ssl_write_change_cipher_spec( ssl ); + break; + + case SSL_CLIENT_FINISHED: + ret = ssl_write_finished( ssl ); + break; + + /* + * <== ChangeCipherSpec + * Finished + */ + case SSL_SERVER_CHANGE_CIPHER_SPEC: + ret = ssl_parse_change_cipher_spec( ssl ); + break; + + case SSL_SERVER_FINISHED: + ret = ssl_parse_finished( ssl ); + break; + + case SSL_FLUSH_BUFFERS: + SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); + ssl->state = SSL_HANDSHAKE_WRAPUP; + break; + + case SSL_HANDSHAKE_WRAPUP: + ssl_handshake_wrapup( ssl ); + break; + + default: + SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) ); + return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ret ); +} +#endif diff --git a/src/libpolarssl/ssl_srv.c b/src/libpolarssl/ssl_srv.c new file mode 100644 index 0000000..861bda3 --- /dev/null +++ b/src/libpolarssl/ssl_srv.c @@ -0,0 +1,1623 @@ +/* + * SSLv3/TLSv1 server-side functions + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_SSL_SRV_C) + +#include "debug.h" +#include "ssl.h" + +#include +#include +#include + +static int ssl_parse_servername_ext( ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + size_t servername_list_size, hostname_len; + const unsigned char *p; + + servername_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( servername_list_size + 2 != len ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + p = buf + 2; + while( servername_list_size > 0 ) + { + hostname_len = ( ( p[1] << 8 ) | p[2] ); + if( hostname_len + 3 > servername_list_size ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( p[0] == TLS_EXT_SERVERNAME_HOSTNAME ) + { + ret = ssl->f_sni( ssl->p_sni, ssl, p + 3, hostname_len ); + if( ret != 0 ) + { + ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL, + SSL_ALERT_MSG_UNRECOGNIZED_NAME ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + return( 0 ); + } + + servername_list_size -= hostname_len + 3; + p += hostname_len + 3; + } + + if( servername_list_size != 0 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + return( 0 ); +} + +static int ssl_parse_renegotiation_info( ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + + if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) + { + if( len != 1 || buf[0] != 0x0 ) + { + SSL_DEBUG_MSG( 1, ( "non-zero length renegotiated connection field" ) ); + + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION; + } + else + { + if( len != 1 + ssl->verify_data_len || + buf[0] != ssl->verify_data_len || + memcmp( buf + 1, ssl->peer_verify_data, ssl->verify_data_len ) != 0 ) + { + SSL_DEBUG_MSG( 1, ( "non-matching renegotiated connection field" ) ); + + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + + return( 0 ); +} + +static int ssl_parse_signature_algorithms_ext( ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t sig_alg_list_size; + const unsigned char *p; + + sig_alg_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( sig_alg_list_size + 2 != len || + sig_alg_list_size %2 != 0 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + p = buf + 2; + while( sig_alg_list_size > 0 ) + { + if( p[1] != SSL_SIG_RSA ) + { + sig_alg_list_size -= 2; + p += 2; + continue; + } +#if defined(POLARSSL_SHA4_C) + if( p[0] == SSL_HASH_SHA512 ) + { + ssl->handshake->sig_alg = SSL_HASH_SHA512; + break; + } + if( p[0] == SSL_HASH_SHA384 ) + { + ssl->handshake->sig_alg = SSL_HASH_SHA384; + break; + } +#endif +#if defined(POLARSSL_SHA2_C) + if( p[0] == SSL_HASH_SHA256 ) + { + ssl->handshake->sig_alg = SSL_HASH_SHA256; + break; + } + if( p[0] == SSL_HASH_SHA224 ) + { + ssl->handshake->sig_alg = SSL_HASH_SHA224; + break; + } +#endif + if( p[0] == SSL_HASH_SHA1 ) + { + ssl->handshake->sig_alg = SSL_HASH_SHA1; + break; + } + if( p[0] == SSL_HASH_MD5 ) + { + ssl->handshake->sig_alg = SSL_HASH_MD5; + break; + } + + sig_alg_list_size -= 2; + p += 2; + } + + SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext: %d", + ssl->handshake->sig_alg ) ); + + return( 0 ); +} + +#if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) +static int ssl_parse_client_hello_v2( ssl_context *ssl ) +{ + int ret; + unsigned int i, j; + size_t n; + unsigned int ciph_len, sess_len, chal_len; + unsigned char *buf, *p; + + SSL_DEBUG_MSG( 2, ( "=> parse client hello v2" ) ); + + if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "client hello v2 illegal for renegotiation" ) ); + + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + buf = ssl->in_hdr; + + SSL_DEBUG_BUF( 4, "record header", buf, 5 ); + + SSL_DEBUG_MSG( 3, ( "client hello v2, message type: %d", + buf[2] ) ); + SSL_DEBUG_MSG( 3, ( "client hello v2, message len.: %d", + ( ( buf[0] & 0x7F ) << 8 ) | buf[1] ) ); + SSL_DEBUG_MSG( 3, ( "client hello v2, max. version: [%d:%d]", + buf[3], buf[4] ) ); + + /* + * SSLv2 Client Hello + * + * Record layer: + * 0 . 1 message length + * + * SSL layer: + * 2 . 2 message type + * 3 . 4 protocol version + */ + if( buf[2] != SSL_HS_CLIENT_HELLO || + buf[3] != SSL_MAJOR_VERSION_3 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + n = ( ( buf[0] << 8 ) | buf[1] ) & 0x7FFF; + + if( n < 17 || n > 512 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->major_ver = SSL_MAJOR_VERSION_3; + ssl->minor_ver = ( buf[4] <= SSL_MINOR_VERSION_3 ) + ? buf[4] : SSL_MINOR_VERSION_3; + + if( ssl->minor_ver < ssl->min_minor_ver ) + { + SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum" + " [%d:%d] < [%d:%d]", ssl->major_ver, ssl->minor_ver, + ssl->min_major_ver, ssl->min_minor_ver ) ); + + ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL, + SSL_ALERT_MSG_PROTOCOL_VERSION ); + return( POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + ssl->max_major_ver = buf[3]; + ssl->max_minor_ver = buf[4]; + + if( ( ret = ssl_fetch_input( ssl, 2 + n ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_fetch_input", ret ); + return( ret ); + } + + ssl->handshake->update_checksum( ssl, buf + 2, n ); + + buf = ssl->in_msg; + n = ssl->in_left - 5; + + /* + * 0 . 1 ciphersuitelist length + * 2 . 3 session id length + * 4 . 5 challenge length + * 6 . .. ciphersuitelist + * .. . .. session id + * .. . .. challenge + */ + SSL_DEBUG_BUF( 4, "record contents", buf, n ); + + ciph_len = ( buf[0] << 8 ) | buf[1]; + sess_len = ( buf[2] << 8 ) | buf[3]; + chal_len = ( buf[4] << 8 ) | buf[5]; + + SSL_DEBUG_MSG( 3, ( "ciph_len: %d, sess_len: %d, chal_len: %d", + ciph_len, sess_len, chal_len ) ); + + /* + * Make sure each parameter length is valid + */ + if( ciph_len < 3 || ( ciph_len % 3 ) != 0 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( sess_len > 32 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( chal_len < 8 || chal_len > 32 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( n != 6 + ciph_len + sess_len + chal_len ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist", + buf + 6, ciph_len ); + SSL_DEBUG_BUF( 3, "client hello, session id", + buf + 6 + ciph_len, sess_len ); + SSL_DEBUG_BUF( 3, "client hello, challenge", + buf + 6 + ciph_len + sess_len, chal_len ); + + p = buf + 6 + ciph_len; + ssl->session_negotiate->length = sess_len; + memset( ssl->session_negotiate->id, 0, sizeof( ssl->session_negotiate->id ) ); + memcpy( ssl->session_negotiate->id, p, ssl->session_negotiate->length ); + + p += sess_len; + memset( ssl->handshake->randbytes, 0, 64 ); + memcpy( ssl->handshake->randbytes + 32 - chal_len, p, chal_len ); + + /* + * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ + for( i = 0, p = buf + 6; i < ciph_len; i += 3, p += 3 ) + { + if( p[0] == 0 && p[1] == 0 && p[2] == SSL_EMPTY_RENEGOTIATION_INFO ) + { + SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) ); + if( ssl->renegotiation == SSL_RENEGOTIATION ) + { + SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV during renegotiation" ) ); + + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION; + break; + } + } + + for( i = 0; ssl->ciphersuites[ssl->minor_ver][i] != 0; i++ ) + { + for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 ) + { + if( p[0] == 0 && + p[1] == 0 && + p[2] == ssl->ciphersuites[ssl->minor_ver][i] ) + goto have_ciphersuite_v2; + } + } + + SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) ); + + return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN ); + +have_ciphersuite_v2: + ssl->session_negotiate->ciphersuite = ssl->ciphersuites[ssl->minor_ver][i]; + ssl_optimize_checksum( ssl, ssl->session_negotiate->ciphersuite ); + + /* + * SSLv2 Client Hello relevant renegotiation security checks + */ + if( ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && + ssl->allow_legacy_renegotiation == SSL_LEGACY_BREAK_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); + + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->in_left = 0; + ssl->state++; + + SSL_DEBUG_MSG( 2, ( "<= parse client hello v2" ) ); + + return( 0 ); +} +#endif /* POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO */ + +static int ssl_parse_client_hello( ssl_context *ssl ) +{ + int ret; + unsigned int i, j; + size_t n; + unsigned int ciph_len, sess_len; + unsigned int comp_len; + unsigned int ext_len = 0; + unsigned char *buf, *p, *ext; + int renegotiation_info_seen = 0; + int handshake_failure = 0; + + SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) ); + + if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE && + ( ret = ssl_fetch_input( ssl, 5 ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_fetch_input", ret ); + return( ret ); + } + + buf = ssl->in_hdr; + +#if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) + if( ( buf[0] & 0x80 ) != 0 ) + return ssl_parse_client_hello_v2( ssl ); +#endif + + SSL_DEBUG_BUF( 4, "record header", buf, 5 ); + + SSL_DEBUG_MSG( 3, ( "client hello v3, message type: %d", + buf[0] ) ); + SSL_DEBUG_MSG( 3, ( "client hello v3, message len.: %d", + ( buf[3] << 8 ) | buf[4] ) ); + SSL_DEBUG_MSG( 3, ( "client hello v3, protocol ver: [%d:%d]", + buf[1], buf[2] ) ); + + /* + * SSLv3 Client Hello + * + * Record layer: + * 0 . 0 message type + * 1 . 2 protocol version + * 3 . 4 message length + */ + if( buf[0] != SSL_MSG_HANDSHAKE || + buf[1] != SSL_MAJOR_VERSION_3 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + n = ( buf[3] << 8 ) | buf[4]; + + if( n < 45 || n > 512 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE && + ( ret = ssl_fetch_input( ssl, 5 + n ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_fetch_input", ret ); + return( ret ); + } + + buf = ssl->in_msg; + if( !ssl->renegotiation ) + n = ssl->in_left - 5; + else + n = ssl->in_msglen; + + ssl->handshake->update_checksum( ssl, buf, n ); + + /* + * SSL layer: + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 protocol version + * 6 . 9 UNIX time() + * 10 . 37 random bytes + * 38 . 38 session id length + * 39 . 38+x session id + * 39+x . 40+x ciphersuitelist length + * 41+x . .. ciphersuitelist + * .. . .. compression alg. + * .. . .. extensions + */ + SSL_DEBUG_BUF( 4, "record contents", buf, n ); + + SSL_DEBUG_MSG( 3, ( "client hello v3, handshake type: %d", + buf[0] ) ); + SSL_DEBUG_MSG( 3, ( "client hello v3, handshake len.: %d", + ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3] ) ); + SSL_DEBUG_MSG( 3, ( "client hello v3, max. version: [%d:%d]", + buf[4], buf[5] ) ); + + /* + * Check the handshake type and protocol version + */ + if( buf[0] != SSL_HS_CLIENT_HELLO || + buf[4] != SSL_MAJOR_VERSION_3 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->major_ver = SSL_MAJOR_VERSION_3; + ssl->minor_ver = ( buf[5] <= SSL_MINOR_VERSION_3 ) + ? buf[5] : SSL_MINOR_VERSION_3; + + if( ssl->minor_ver < ssl->min_minor_ver ) + { + SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum" + " [%d:%d] < [%d:%d]", ssl->major_ver, ssl->minor_ver, + ssl->min_major_ver, ssl->min_minor_ver ) ); + + ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL, + SSL_ALERT_MSG_PROTOCOL_VERSION ); + + return( POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + ssl->max_major_ver = buf[4]; + ssl->max_minor_ver = buf[5]; + + memcpy( ssl->handshake->randbytes, buf + 6, 32 ); + + /* + * Check the handshake message length + */ + if( buf[1] != 0 || n != (unsigned int) 4 + ( ( buf[2] << 8 ) | buf[3] ) ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Check the session length + */ + sess_len = buf[38]; + + if( sess_len > 32 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->session_negotiate->length = sess_len; + memset( ssl->session_negotiate->id, 0, + sizeof( ssl->session_negotiate->id ) ); + memcpy( ssl->session_negotiate->id, buf + 39, + ssl->session_negotiate->length ); + + /* + * Check the ciphersuitelist length + */ + ciph_len = ( buf[39 + sess_len] << 8 ) + | ( buf[40 + sess_len] ); + + if( ciph_len < 2 || ciph_len > 256 || ( ciph_len % 2 ) != 0 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Check the compression algorithms length + */ + comp_len = buf[41 + sess_len + ciph_len]; + + if( comp_len < 1 || comp_len > 16 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Check the extension length + */ + if( n > 42 + sess_len + ciph_len + comp_len ) + { + ext_len = ( buf[42 + sess_len + ciph_len + comp_len] << 8 ) + | ( buf[43 + sess_len + ciph_len + comp_len] ); + + if( ( ext_len > 0 && ext_len < 4 ) || + n != 44 + sess_len + ciph_len + comp_len + ext_len ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + SSL_DEBUG_BUF( 3, "Ext", buf + 44 + sess_len + ciph_len + comp_len, ext_len); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + + ssl->session_negotiate->compression = SSL_COMPRESS_NULL; +#if defined(POLARSSL_ZLIB_SUPPORT) + for( i = 0; i < comp_len; ++i ) + { + if( buf[42 + sess_len + ciph_len + i] == SSL_COMPRESS_DEFLATE ) + { + ssl->session_negotiate->compression = SSL_COMPRESS_DEFLATE; + break; + } + } +#endif + + SSL_DEBUG_BUF( 3, "client hello, random bytes", + buf + 6, 32 ); + SSL_DEBUG_BUF( 3, "client hello, session id", + buf + 38, sess_len ); + SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist", + buf + 41 + sess_len, ciph_len ); + SSL_DEBUG_BUF( 3, "client hello, compression", + buf + 42 + sess_len + ciph_len, comp_len ); + + /* + * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ + for( i = 0, p = buf + 41 + sess_len; i < ciph_len; i += 2, p += 2 ) + { + if( p[0] == 0 && p[1] == SSL_EMPTY_RENEGOTIATION_INFO ) + { + SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) ); + if( ssl->renegotiation == SSL_RENEGOTIATION ) + { + SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV during renegotiation" ) ); + + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION; + break; + } + } + + /* + * Search for a matching ciphersuite + */ + for( i = 0; ssl->ciphersuites[ssl->minor_ver][i] != 0; i++ ) + { + for( j = 0, p = buf + 41 + sess_len; j < ciph_len; + j += 2, p += 2 ) + { + if( p[0] == 0 && p[1] == ssl->ciphersuites[ssl->minor_ver][i] ) + goto have_ciphersuite; + } + } + + SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) ); + + return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN ); + +have_ciphersuite: + ssl->session_negotiate->ciphersuite = ssl->ciphersuites[ssl->minor_ver][i]; + ssl_optimize_checksum( ssl, ssl->session_negotiate->ciphersuite ); + + ext = buf + 44 + sess_len + ciph_len + comp_len; + + while( ext_len ) + { + unsigned int ext_id = ( ( ext[0] << 8 ) + | ( ext[1] ) ); + unsigned int ext_size = ( ( ext[2] << 8 ) + | ( ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + switch( ext_id ) + { + case TLS_EXT_SERVERNAME: + SSL_DEBUG_MSG( 3, ( "found ServerName extension" ) ); + if( ssl->f_sni == NULL ) + break; + + ret = ssl_parse_servername_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + + case TLS_EXT_RENEGOTIATION_INFO: + SSL_DEBUG_MSG( 3, ( "found renegotiation extension" ) ); + renegotiation_info_seen = 1; + + ret = ssl_parse_renegotiation_info( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + + case TLS_EXT_SIG_ALG: + SSL_DEBUG_MSG( 3, ( "found signature_algorithms extension" ) ); + if( ssl->renegotiation == SSL_RENEGOTIATION ) + break; + + ret = ssl_parse_signature_algorithms_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + + default: + SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", + ext_id ) ); + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + + /* + * Renegotiation security checks + */ + if( ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && + ssl->allow_legacy_renegotiation == SSL_LEGACY_BREAK_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); + handshake_failure = 1; + } + else if( ssl->renegotiation == SSL_RENEGOTIATION && + ssl->secure_renegotiation == SSL_SECURE_RENEGOTIATION && + renegotiation_info_seen == 0 ) + { + SSL_DEBUG_MSG( 1, ( "renegotiation_info extension missing (secure)" ) ); + handshake_failure = 1; + } + else if( ssl->renegotiation == SSL_RENEGOTIATION && + ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && + ssl->allow_legacy_renegotiation == SSL_LEGACY_NO_RENEGOTIATION ) + { + SSL_DEBUG_MSG( 1, ( "legacy renegotiation not allowed" ) ); + handshake_failure = 1; + } + else if( ssl->renegotiation == SSL_RENEGOTIATION && + ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && + renegotiation_info_seen == 1 ) + { + SSL_DEBUG_MSG( 1, ( "renegotiation_info extension present (legacy)" ) ); + handshake_failure = 1; + } + + if( handshake_failure == 1 ) + { + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->in_left = 0; + ssl->state++; + + SSL_DEBUG_MSG( 2, ( "<= parse client hello" ) ); + + return( 0 ); +} + +static int ssl_write_server_hello( ssl_context *ssl ) +{ + time_t t; + int ret, n; + size_t ext_len = 0; + unsigned char *buf, *p; + + SSL_DEBUG_MSG( 2, ( "=> write server hello" ) ); + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 protocol version + * 6 . 9 UNIX time() + * 10 . 37 random bytes + */ + buf = ssl->out_msg; + p = buf + 4; + + *p++ = (unsigned char) ssl->major_ver; + *p++ = (unsigned char) ssl->minor_ver; + + SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [%d:%d]", + buf[4], buf[5] ) ); + + t = time( NULL ); + *p++ = (unsigned char)( t >> 24 ); + *p++ = (unsigned char)( t >> 16 ); + *p++ = (unsigned char)( t >> 8 ); + *p++ = (unsigned char)( t ); + + SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) ); + + if( ( ret = ssl->f_rng( ssl->p_rng, p, 28 ) ) != 0 ) + return( ret ); + + p += 28; + + memcpy( ssl->handshake->randbytes + 32, buf + 6, 32 ); + + SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 6, 32 ); + + /* + * 38 . 38 session id length + * 39 . 38+n session id + * 39+n . 40+n chosen ciphersuite + * 41+n . 41+n chosen compression alg. + */ + ssl->session_negotiate->length = n = 32; + *p++ = (unsigned char) ssl->session_negotiate->length; + + if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE || + ssl->f_get_cache == NULL || + ssl->f_get_cache( ssl->p_get_cache, ssl->session_negotiate ) != 0 ) + { + /* + * Not found, create a new session id + */ + ssl->handshake->resume = 0; + ssl->state++; + + if( ( ret = ssl->f_rng( ssl->p_rng, ssl->session_negotiate->id, + n ) ) != 0 ) + return( ret ); + } + else + { + /* + * Found a matching session, resuming it + */ + ssl->handshake->resume = 1; + ssl->state = SSL_SERVER_CHANGE_CIPHER_SPEC; + + if( ( ret = ssl_derive_keys( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_derive_keys", ret ); + return( ret ); + } + } + + memcpy( p, ssl->session_negotiate->id, ssl->session_negotiate->length ); + p += ssl->session_negotiate->length; + + SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) ); + SSL_DEBUG_BUF( 3, "server hello, session id", buf + 39, n ); + SSL_DEBUG_MSG( 3, ( "%s session has been resumed", + ssl->handshake->resume ? "a" : "no" ) ); + + *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite >> 8 ); + *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite ); + *p++ = (unsigned char)( ssl->session_negotiate->compression ); + + SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %d", + ssl->session_negotiate->ciphersuite ) ); + SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", + ssl->session_negotiate->compression ) ); + + if( ssl->secure_renegotiation == SSL_SECURE_RENEGOTIATION ) + { + SSL_DEBUG_MSG( 3, ( "server hello, prepping for secure renegotiation extension" ) ); + ext_len += 5 + ssl->verify_data_len * 2; + + SSL_DEBUG_MSG( 3, ( "server hello, total extension length: %d", + ext_len ) ); + + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len ) & 0xFF ); + + /* + * Secure renegotiation + */ + SSL_DEBUG_MSG( 3, ( "client hello, secure renegotiation extension" ) ); + + *p++ = (unsigned char)( ( TLS_EXT_RENEGOTIATION_INFO >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( TLS_EXT_RENEGOTIATION_INFO ) & 0xFF ); + + *p++ = 0x00; + *p++ = ( ssl->verify_data_len * 2 + 1 ) & 0xFF; + *p++ = ssl->verify_data_len * 2 & 0xFF; + + memcpy( p, ssl->peer_verify_data, ssl->verify_data_len ); + p += ssl->verify_data_len; + memcpy( p, ssl->own_verify_data, ssl->verify_data_len ); + p += ssl->verify_data_len; + } + + ssl->out_msglen = p - buf; + ssl->out_msgtype = SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = SSL_HS_SERVER_HELLO; + + ret = ssl_write_record( ssl ); + + SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); + + return( ret ); +} + +static int ssl_write_certificate_request( ssl_context *ssl ) +{ + int ret; + size_t n = 0, dn_size, total_dn_size; + unsigned char *buf, *p; + const x509_cert *crt; + + SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) ); + + ssl->state++; + + if( ssl->authmode == SSL_VERIFY_NONE ) + { + SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) ); + return( 0 ); + } + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 4 cert type count + * 5 .. m-1 cert types + * m .. m+1 sig alg length (TLS 1.2 only) + * m+1 .. n-1 SignatureAndHashAlgorithms (TLS 1.2 only) + * n .. n+1 length of all DNs + * n+2 .. n+3 length of DN 1 + * n+4 .. ... Distinguished Name #1 + * ... .. ... length of DN 2, etc. + */ + buf = ssl->out_msg; + p = buf + 4; + + /* + * At the moment, only RSA certificates are supported + */ + *p++ = 1; + *p++ = SSL_CERT_TYPE_RSA_SIGN; + + /* + * Add signature_algorithms for verify (TLS 1.2) + * Only add current running algorithm that is already required for + * requested ciphersuite. + * + * Length is always 2 + */ + if( ssl->minor_ver == SSL_MINOR_VERSION_3 ) + { + ssl->handshake->verify_sig_alg = SSL_HASH_SHA256; + + *p++ = 0; + *p++ = 2; + + if( ssl->session_negotiate->ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ) + { + ssl->handshake->verify_sig_alg = SSL_HASH_SHA384; + } + + *p++ = ssl->handshake->verify_sig_alg; + *p++ = SSL_SIG_RSA; + + n += 4; + } + + p += 2; + crt = ssl->ca_chain; + + total_dn_size = 0; + while( crt != NULL && crt->version != 0) + { + if( p - buf > 4096 ) + break; + + dn_size = crt->subject_raw.len; + *p++ = (unsigned char)( dn_size >> 8 ); + *p++ = (unsigned char)( dn_size ); + memcpy( p, crt->subject_raw.p, dn_size ); + p += dn_size; + + SSL_DEBUG_BUF( 3, "requested DN", p, dn_size ); + + total_dn_size += 2 + dn_size; + crt = crt->next; + } + + ssl->out_msglen = p - buf; + ssl->out_msgtype = SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = SSL_HS_CERTIFICATE_REQUEST; + ssl->out_msg[6 + n] = (unsigned char)( total_dn_size >> 8 ); + ssl->out_msg[7 + n] = (unsigned char)( total_dn_size ); + + ret = ssl_write_record( ssl ); + + SSL_DEBUG_MSG( 2, ( "<= write certificate request" ) ); + + return( ret ); +} + +static int ssl_write_server_key_exchange( ssl_context *ssl ) +{ +#if defined(POLARSSL_DHM_C) + int ret; + size_t n, rsa_key_len = 0; + unsigned char hash[64]; + int hash_id = 0; + unsigned int hashlen = 0; +#endif + + SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); + + if( ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_DES_CBC_SHA && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 && + ssl->session_negotiate->ciphersuite != TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ) + { + SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) ); + ssl->state++; + return( 0 ); + } + +#if !defined(POLARSSL_DHM_C) + SSL_DEBUG_MSG( 1, ( "support for dhm is not available" ) ); + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); +#else + + if( ssl->rsa_key == NULL ) + { + SSL_DEBUG_MSG( 1, ( "got no private key" ) ); + return( POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Ephemeral DH parameters: + * + * struct { + * opaque dh_p<1..2^16-1>; + * opaque dh_g<1..2^16-1>; + * opaque dh_Ys<1..2^16-1>; + * } ServerDHParams; + */ + if( ( ret = mpi_copy( &ssl->handshake->dhm_ctx.P, &ssl->dhm_P ) ) != 0 || + ( ret = mpi_copy( &ssl->handshake->dhm_ctx.G, &ssl->dhm_G ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "mpi_copy", ret ); + return( ret ); + } + + if( ( ret = dhm_make_params( &ssl->handshake->dhm_ctx, + mpi_size( &ssl->handshake->dhm_ctx.P ), + ssl->out_msg + 4, + &n, ssl->f_rng, ssl->p_rng ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "dhm_make_params", ret ); + return( ret ); + } + + SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X ); + SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P ); + SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->handshake->dhm_ctx.G ); + SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->handshake->dhm_ctx.GX ); + + if( ssl->minor_ver != SSL_MINOR_VERSION_3 ) + { + md5_context md5; + sha1_context sha1; + + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(ClientHello.random + ServerHello.random + * + ServerParams); + * sha_hash + * SHA(ClientHello.random + ServerHello.random + * + ServerParams); + */ + md5_starts( &md5 ); + md5_update( &md5, ssl->handshake->randbytes, 64 ); + md5_update( &md5, ssl->out_msg + 4, n ); + md5_finish( &md5, hash ); + + sha1_starts( &sha1 ); + sha1_update( &sha1, ssl->handshake->randbytes, 64 ); + sha1_update( &sha1, ssl->out_msg + 4, n ); + sha1_finish( &sha1, hash + 16 ); + + hashlen = 36; + hash_id = SIG_RSA_RAW; + } + else + { + /* + * digitally-signed struct { + * opaque client_random[32]; + * opaque server_random[32]; + * ServerDHParams params; + * }; + */ +#if defined(POLARSSL_SHA4_C) + if( ssl->handshake->sig_alg == SSL_HASH_SHA512 ) + { + sha4_context sha4; + + sha4_starts( &sha4, 0 ); + sha4_update( &sha4, ssl->handshake->randbytes, 64 ); + sha4_update( &sha4, ssl->out_msg + 4, n ); + sha4_finish( &sha4, hash ); + + hashlen = 64; + hash_id = SIG_RSA_SHA512; + } + else if( ssl->handshake->sig_alg == SSL_HASH_SHA384 ) + { + sha4_context sha4; + + sha4_starts( &sha4, 1 ); + sha4_update( &sha4, ssl->handshake->randbytes, 64 ); + sha4_update( &sha4, ssl->out_msg + 4, n ); + sha4_finish( &sha4, hash ); + + hashlen = 48; + hash_id = SIG_RSA_SHA384; + } + else +#endif +#if defined(POLARSSL_SHA2_C) + if( ssl->handshake->sig_alg == SSL_HASH_SHA256 ) + { + sha2_context sha2; + + sha2_starts( &sha2, 0 ); + sha2_update( &sha2, ssl->handshake->randbytes, 64 ); + sha2_update( &sha2, ssl->out_msg + 4, n ); + sha2_finish( &sha2, hash ); + + hashlen = 32; + hash_id = SIG_RSA_SHA256; + } + else if( ssl->handshake->sig_alg == SSL_HASH_SHA224 ) + { + sha2_context sha2; + + sha2_starts( &sha2, 1 ); + sha2_update( &sha2, ssl->handshake->randbytes, 64 ); + sha2_update( &sha2, ssl->out_msg + 4, n ); + sha2_finish( &sha2, hash ); + + hashlen = 24; + hash_id = SIG_RSA_SHA224; + } + else +#endif + if( ssl->handshake->sig_alg == SSL_HASH_SHA1 ) + { + sha1_context sha1; + + sha1_starts( &sha1 ); + sha1_update( &sha1, ssl->handshake->randbytes, 64 ); + sha1_update( &sha1, ssl->out_msg + 4, n ); + sha1_finish( &sha1, hash ); + + hashlen = 20; + hash_id = SIG_RSA_SHA1; + } + else if( ssl->handshake->sig_alg == SSL_HASH_MD5 ) + { + md5_context md5; + + md5_starts( &md5 ); + md5_update( &md5, ssl->handshake->randbytes, 64 ); + md5_update( &md5, ssl->out_msg + 4, n ); + md5_finish( &md5, hash ); + + hashlen = 16; + hash_id = SIG_RSA_MD5; + } + } + + SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen ); + + if ( ssl->rsa_key ) + rsa_key_len = ssl->rsa_key_len( ssl->rsa_key ); + + if( ssl->minor_ver == SSL_MINOR_VERSION_3 ) + { + ssl->out_msg[4 + n] = ssl->handshake->sig_alg; + ssl->out_msg[5 + n] = SSL_SIG_RSA; + + n += 2; + } + + ssl->out_msg[4 + n] = (unsigned char)( rsa_key_len >> 8 ); + ssl->out_msg[5 + n] = (unsigned char)( rsa_key_len ); + + if ( ssl->rsa_key ) + { + ret = ssl->rsa_sign( ssl->rsa_key, ssl->f_rng, ssl->p_rng, + RSA_PRIVATE, + hash_id, hashlen, hash, + ssl->out_msg + 6 + n ); + } + + if( ret != 0 ) + { + SSL_DEBUG_RET( 1, "pkcs1_sign", ret ); + return( ret ); + } + + SSL_DEBUG_BUF( 3, "my RSA sig", ssl->out_msg + 6 + n, rsa_key_len ); + + ssl->out_msglen = 6 + n + rsa_key_len; + ssl->out_msgtype = SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = SSL_HS_SERVER_KEY_EXCHANGE; + + ssl->state++; + + if( ( ret = ssl_write_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + + SSL_DEBUG_MSG( 2, ( "<= write server key exchange" ) ); + + return( 0 ); +#endif +} + +static int ssl_write_server_hello_done( ssl_context *ssl ) +{ + int ret; + + SSL_DEBUG_MSG( 2, ( "=> write server hello done" ) ); + + ssl->out_msglen = 4; + ssl->out_msgtype = SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = SSL_HS_SERVER_HELLO_DONE; + + ssl->state++; + + if( ( ret = ssl_write_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + + SSL_DEBUG_MSG( 2, ( "<= write server hello done" ) ); + + return( 0 ); +} + +static int ssl_parse_client_key_exchange( ssl_context *ssl ) +{ + int ret; + size_t i, n = 0; + + SSL_DEBUG_MSG( 2, ( "=> parse client key exchange" ) ); + + if( ( ret = ssl_read_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != SSL_MSG_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ssl->in_msg[0] != SSL_HS_CLIENT_KEY_EXCHANGE ) + { + SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_DES_CBC_SHA || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 || + ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ) + { +#if !defined(POLARSSL_DHM_C) + SSL_DEBUG_MSG( 1, ( "support for dhm is not available" ) ); + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); +#else + /* + * Receive G^Y mod P, premaster = (G^Y)^X mod P + */ + n = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5]; + + if( n < 1 || n > ssl->handshake->dhm_ctx.len || + n + 6 != ssl->in_hslen ) + { + SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ( ret = dhm_read_public( &ssl->handshake->dhm_ctx, + ssl->in_msg + 6, n ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "dhm_read_public", ret ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_DHM_RP ); + } + + SSL_DEBUG_MPI( 3, "DHM: GY", &ssl->handshake->dhm_ctx.GY ); + + ssl->handshake->pmslen = ssl->handshake->dhm_ctx.len; + + if( ( ret = dhm_calc_secret( &ssl->handshake->dhm_ctx, + ssl->handshake->premaster, + &ssl->handshake->pmslen ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "dhm_calc_secret", ret ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_DHM_CS ); + } + + SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K ); +#endif + } + else + { + if( ssl->rsa_key == NULL ) + { + SSL_DEBUG_MSG( 1, ( "got no private key" ) ); + return( POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Decrypt the premaster using own private RSA key + */ + i = 4; + if( ssl->rsa_key ) + n = ssl->rsa_key_len( ssl->rsa_key ); + ssl->handshake->pmslen = 48; + + if( ssl->minor_ver != SSL_MINOR_VERSION_0 ) + { + i += 2; + if( ssl->in_msg[4] != ( ( n >> 8 ) & 0xFF ) || + ssl->in_msg[5] != ( ( n ) & 0xFF ) ) + { + SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + } + + if( ssl->in_hslen != i + n ) + { + SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ssl->rsa_key ) { + ret = ssl->rsa_decrypt( ssl->rsa_key, RSA_PRIVATE, + &ssl->handshake->pmslen, + ssl->in_msg + i, + ssl->handshake->premaster, + sizeof(ssl->handshake->premaster) ); + } + + if( ret != 0 || ssl->handshake->pmslen != 48 || + ssl->handshake->premaster[0] != ssl->max_major_ver || + ssl->handshake->premaster[1] != ssl->max_minor_ver ) + { + SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + + /* + * Protection against Bleichenbacher's attack: + * invalid PKCS#1 v1.5 padding must not cause + * the connection to end immediately; instead, + * send a bad_record_mac later in the handshake. + */ + ssl->handshake->pmslen = 48; + + ret = ssl->f_rng( ssl->p_rng, ssl->handshake->premaster, + ssl->handshake->pmslen ); + if( ret != 0 ) + return( ret ); + } + } + + if( ( ret = ssl_derive_keys( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_derive_keys", ret ); + return( ret ); + } + + ssl->state++; + + SSL_DEBUG_MSG( 2, ( "<= parse client key exchange" ) ); + + return( 0 ); +} + +static int ssl_parse_certificate_verify( ssl_context *ssl ) +{ + int ret; + size_t n = 0, n1, n2; + unsigned char hash[48]; + int hash_id; + unsigned int hashlen; + + SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) ); + + if( ssl->session_negotiate->peer_cert == NULL ) + { + SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + ssl->handshake->calc_verify( ssl, hash ); + + if( ( ret = ssl_read_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_read_record", ret ); + return( ret ); + } + + ssl->state++; + + if( ssl->in_msgtype != SSL_MSG_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + if( ssl->in_msg[0] != SSL_HS_CERTIFICATE_VERIFY ) + { + SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + if( ssl->minor_ver == SSL_MINOR_VERSION_3 ) + { + /* + * As server we know we either have SSL_HASH_SHA384 or + * SSL_HASH_SHA256 + */ + if( ssl->in_msg[4] != ssl->handshake->verify_sig_alg || + ssl->in_msg[5] != SSL_SIG_RSA ) + { + SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg for verify message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + if( ssl->handshake->verify_sig_alg == SSL_HASH_SHA384 ) + { + hashlen = 48; + hash_id = SIG_RSA_SHA384; + } + else + { + hashlen = 32; + hash_id = SIG_RSA_SHA256; + } + + n += 2; + } + else + { + hashlen = 36; + hash_id = SIG_RSA_RAW; + } + + n1 = ssl->session_negotiate->peer_cert->rsa.len; + n2 = ( ssl->in_msg[4 + n] << 8 ) | ssl->in_msg[5 + n]; + + if( n + n1 + 6 != ssl->in_hslen || n1 != n2 ) + { + SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + ret = rsa_pkcs1_verify( &ssl->session_negotiate->peer_cert->rsa, RSA_PUBLIC, + hash_id, hashlen, hash, ssl->in_msg + 6 + n ); + if( ret != 0 ) + { + SSL_DEBUG_RET( 1, "rsa_pkcs1_verify", ret ); + return( ret ); + } + + SSL_DEBUG_MSG( 2, ( "<= parse certificate verify" ) ); + + return( 0 ); +} + +/* + * SSL handshake -- server side -- single step + */ +int ssl_handshake_server_step( ssl_context *ssl ) +{ + int ret = 0; + + if( ssl->state == SSL_HANDSHAKE_OVER ) + return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + + SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) ); + + if( ( ret = ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + switch( ssl->state ) + { + case SSL_HELLO_REQUEST: + ssl->state = SSL_CLIENT_HELLO; + break; + + /* + * <== ClientHello + */ + case SSL_CLIENT_HELLO: + ret = ssl_parse_client_hello( ssl ); + break; + + /* + * ==> ServerHello + * Certificate + * ( ServerKeyExchange ) + * ( CertificateRequest ) + * ServerHelloDone + */ + case SSL_SERVER_HELLO: + ret = ssl_write_server_hello( ssl ); + break; + + case SSL_SERVER_CERTIFICATE: + ret = ssl_write_certificate( ssl ); + break; + + case SSL_SERVER_KEY_EXCHANGE: + ret = ssl_write_server_key_exchange( ssl ); + break; + + case SSL_CERTIFICATE_REQUEST: + ret = ssl_write_certificate_request( ssl ); + break; + + case SSL_SERVER_HELLO_DONE: + ret = ssl_write_server_hello_done( ssl ); + break; + + /* + * <== ( Certificate/Alert ) + * ClientKeyExchange + * ( CertificateVerify ) + * ChangeCipherSpec + * Finished + */ + case SSL_CLIENT_CERTIFICATE: + ret = ssl_parse_certificate( ssl ); + break; + + case SSL_CLIENT_KEY_EXCHANGE: + ret = ssl_parse_client_key_exchange( ssl ); + break; + + case SSL_CERTIFICATE_VERIFY: + ret = ssl_parse_certificate_verify( ssl ); + break; + + case SSL_CLIENT_CHANGE_CIPHER_SPEC: + ret = ssl_parse_change_cipher_spec( ssl ); + break; + + case SSL_CLIENT_FINISHED: + ret = ssl_parse_finished( ssl ); + break; + + /* + * ==> ChangeCipherSpec + * Finished + */ + case SSL_SERVER_CHANGE_CIPHER_SPEC: + ret = ssl_write_change_cipher_spec( ssl ); + break; + + case SSL_SERVER_FINISHED: + ret = ssl_write_finished( ssl ); + break; + + case SSL_FLUSH_BUFFERS: + SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); + ssl->state = SSL_HANDSHAKE_WRAPUP; + break; + + case SSL_HANDSHAKE_WRAPUP: + ssl_handshake_wrapup( ssl ); + break; + + default: + SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) ); + return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ret ); +} +#endif diff --git a/src/libpolarssl/ssl_tls.c b/src/libpolarssl/ssl_tls.c new file mode 100644 index 0000000..788b2f7 --- /dev/null +++ b/src/libpolarssl/ssl_tls.c @@ -0,0 +1,3991 @@ +/* + * SSLv3/TLSv1 shared functions + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The SSL 3.0 specification was drafted by Netscape in 1996, + * and became an IETF standard in 1999. + * + * http://wp.netscape.com/eng/ssl3/ + * http://www.ietf.org/rfc/rfc2246.txt + * http://www.ietf.org/rfc/rfc4346.txt + */ + +#include "config.h" + +#if defined(POLARSSL_SSL_TLS_C) + +#include "aes.h" +#include "arc4.h" +#include "camellia.h" +#include "des.h" +#include "debug.h" +#include "ssl.h" +#include "sha2.h" + +#if defined(POLARSSL_GCM_C) +#include "gcm.h" +#endif + +#include +#include + +#if defined _MSC_VER && !defined strcasecmp +#define strcasecmp _stricmp +#endif + +#if defined(POLARSSL_SSL_HW_RECORD_ACCEL) +int (*ssl_hw_record_init)(ssl_context *ssl, + const unsigned char *key_enc, const unsigned char *key_dec, + const unsigned char *iv_enc, const unsigned char *iv_dec, + const unsigned char *mac_enc, const unsigned char *mac_dec) = NULL; +int (*ssl_hw_record_reset)(ssl_context *ssl) = NULL; +int (*ssl_hw_record_write)(ssl_context *ssl) = NULL; +int (*ssl_hw_record_read)(ssl_context *ssl) = NULL; +int (*ssl_hw_record_finish)(ssl_context *ssl) = NULL; +#endif + +static int ssl_rsa_decrypt( void *ctx, int mode, size_t *olen, + const unsigned char *input, unsigned char *output, + size_t output_max_len ) +{ + return rsa_pkcs1_decrypt( (rsa_context *) ctx, mode, olen, input, output, + output_max_len ); +} + +static int ssl_rsa_sign( void *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + int mode, int hash_id, unsigned int hashlen, + const unsigned char *hash, unsigned char *sig ) +{ + return rsa_pkcs1_sign( (rsa_context *) ctx, f_rng, p_rng, mode, hash_id, + hashlen, hash, sig ); +} + +static size_t ssl_rsa_key_len( void *ctx ) +{ + return ( (rsa_context *) ctx )->len; +} + +/* + * Key material generation + */ +static int ssl3_prf( unsigned char *secret, size_t slen, char *label, + unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t i; + md5_context md5; + sha1_context sha1; + unsigned char padding[16]; + unsigned char sha1sum[20]; + ((void)label); + + /* + * SSLv3: + * block = + * MD5( secret + SHA1( 'A' + secret + random ) ) + + * MD5( secret + SHA1( 'BB' + secret + random ) ) + + * MD5( secret + SHA1( 'CCC' + secret + random ) ) + + * ... + */ + for( i = 0; i < dlen / 16; i++ ) + { + memset( padding, 'A' + i, 1 + i ); + + sha1_starts( &sha1 ); + sha1_update( &sha1, padding, 1 + i ); + sha1_update( &sha1, secret, slen ); + sha1_update( &sha1, random, rlen ); + sha1_finish( &sha1, sha1sum ); + + md5_starts( &md5 ); + md5_update( &md5, secret, slen ); + md5_update( &md5, sha1sum, 20 ); + md5_finish( &md5, dstbuf + i * 16 ); + } + + memset( &md5, 0, sizeof( md5 ) ); + memset( &sha1, 0, sizeof( sha1 ) ); + + memset( padding, 0, sizeof( padding ) ); + memset( sha1sum, 0, sizeof( sha1sum ) ); + + return( 0 ); +} + +static int tls1_prf( unsigned char *secret, size_t slen, char *label, + unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t nb, hs; + size_t i, j, k; + unsigned char *S1, *S2; + unsigned char tmp[128]; + unsigned char h_i[20]; + + if( sizeof( tmp ) < 20 + strlen( label ) + rlen ) + return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + + hs = ( slen + 1 ) / 2; + S1 = secret; + S2 = secret + slen - hs; + + nb = strlen( label ); + memcpy( tmp + 20, label, nb ); + memcpy( tmp + 20 + nb, random, rlen ); + nb += rlen; + + /* + * First compute P_md5(secret,label+random)[0..dlen] + */ + md5_hmac( S1, hs, tmp + 20, nb, 4 + tmp ); + + for( i = 0; i < dlen; i += 16 ) + { + md5_hmac( S1, hs, 4 + tmp, 16 + nb, h_i ); + md5_hmac( S1, hs, 4 + tmp, 16, 4 + tmp ); + + k = ( i + 16 > dlen ) ? dlen % 16 : 16; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = h_i[j]; + } + + /* + * XOR out with P_sha1(secret,label+random)[0..dlen] + */ + sha1_hmac( S2, hs, tmp + 20, nb, tmp ); + + for( i = 0; i < dlen; i += 20 ) + { + sha1_hmac( S2, hs, tmp, 20 + nb, h_i ); + sha1_hmac( S2, hs, tmp, 20, tmp ); + + k = ( i + 20 > dlen ) ? dlen % 20 : 20; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = (unsigned char)( dstbuf[i + j] ^ h_i[j] ); + } + + memset( tmp, 0, sizeof( tmp ) ); + memset( h_i, 0, sizeof( h_i ) ); + + return( 0 ); +} + +static int tls_prf_sha256( unsigned char *secret, size_t slen, char *label, + unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t nb; + size_t i, j, k; + unsigned char tmp[128]; + unsigned char h_i[32]; + + if( sizeof( tmp ) < 32 + strlen( label ) + rlen ) + return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + + nb = strlen( label ); + memcpy( tmp + 32, label, nb ); + memcpy( tmp + 32 + nb, random, rlen ); + nb += rlen; + + /* + * Compute P_(secret, label + random)[0..dlen] + */ + sha2_hmac( secret, slen, tmp + 32, nb, tmp, 0 ); + + for( i = 0; i < dlen; i += 32 ) + { + sha2_hmac( secret, slen, tmp, 32 + nb, h_i, 0 ); + sha2_hmac( secret, slen, tmp, 32, tmp, 0 ); + + k = ( i + 32 > dlen ) ? dlen % 32 : 32; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = h_i[j]; + } + + memset( tmp, 0, sizeof( tmp ) ); + memset( h_i, 0, sizeof( h_i ) ); + + return( 0 ); +} + +#if defined(POLARSSL_SHA4_C) +static int tls_prf_sha384( unsigned char *secret, size_t slen, char *label, + unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t nb; + size_t i, j, k; + unsigned char tmp[128]; + unsigned char h_i[48]; + + if( sizeof( tmp ) < 48 + strlen( label ) + rlen ) + return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + + nb = strlen( label ); + memcpy( tmp + 48, label, nb ); + memcpy( tmp + 48 + nb, random, rlen ); + nb += rlen; + + /* + * Compute P_(secret, label + random)[0..dlen] + */ + sha4_hmac( secret, slen, tmp + 48, nb, tmp, 1 ); + + for( i = 0; i < dlen; i += 48 ) + { + sha4_hmac( secret, slen, tmp, 48 + nb, h_i, 1 ); + sha4_hmac( secret, slen, tmp, 48, tmp, 1 ); + + k = ( i + 48 > dlen ) ? dlen % 48 : 48; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = h_i[j]; + } + + memset( tmp, 0, sizeof( tmp ) ); + memset( h_i, 0, sizeof( h_i ) ); + + return( 0 ); +} +#endif + +static void ssl_update_checksum_start(ssl_context *, unsigned char *, size_t); +static void ssl_update_checksum_md5sha1(ssl_context *, unsigned char *, size_t); +static void ssl_update_checksum_sha256(ssl_context *, unsigned char *, size_t); + +static void ssl_calc_verify_ssl(ssl_context *,unsigned char *); +static void ssl_calc_verify_tls(ssl_context *,unsigned char *); +static void ssl_calc_verify_tls_sha256(ssl_context *,unsigned char *); + +static void ssl_calc_finished_ssl(ssl_context *,unsigned char *,int); +static void ssl_calc_finished_tls(ssl_context *,unsigned char *,int); +static void ssl_calc_finished_tls_sha256(ssl_context *,unsigned char *,int); + +#if defined(POLARSSL_SHA4_C) +static void ssl_update_checksum_sha384(ssl_context *, unsigned char *, size_t); +static void ssl_calc_verify_tls_sha384(ssl_context *,unsigned char *); +static void ssl_calc_finished_tls_sha384(ssl_context *,unsigned char *,int); +#endif + +int ssl_derive_keys( ssl_context *ssl ) +{ + unsigned char tmp[64]; + unsigned char keyblk[256]; + unsigned char *key1; + unsigned char *key2; + unsigned int iv_copy_len; + ssl_session *session = ssl->session_negotiate; + ssl_transform *transform = ssl->transform_negotiate; + ssl_handshake_params *handshake = ssl->handshake; + + SSL_DEBUG_MSG( 2, ( "=> derive keys" ) ); + + /* + * Set appropriate PRF function and other SSL / TLS / TLS1.2 functions + */ + if( ssl->minor_ver == SSL_MINOR_VERSION_0 ) + { + handshake->tls_prf = ssl3_prf; + handshake->calc_verify = ssl_calc_verify_ssl; + handshake->calc_finished = ssl_calc_finished_ssl; + } + else if( ssl->minor_ver < SSL_MINOR_VERSION_3 ) + { + handshake->tls_prf = tls1_prf; + handshake->calc_verify = ssl_calc_verify_tls; + handshake->calc_finished = ssl_calc_finished_tls; + } +#if defined(POLARSSL_SHA4_C) + else if( session->ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 || + session->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ) + { + handshake->tls_prf = tls_prf_sha384; + handshake->calc_verify = ssl_calc_verify_tls_sha384; + handshake->calc_finished = ssl_calc_finished_tls_sha384; + } +#endif + else + { + handshake->tls_prf = tls_prf_sha256; + handshake->calc_verify = ssl_calc_verify_tls_sha256; + handshake->calc_finished = ssl_calc_finished_tls_sha256; + } + + /* + * SSLv3: + * master = + * MD5( premaster + SHA1( 'A' + premaster + randbytes ) ) + + * MD5( premaster + SHA1( 'BB' + premaster + randbytes ) ) + + * MD5( premaster + SHA1( 'CCC' + premaster + randbytes ) ) + * + * TLSv1: + * master = PRF( premaster, "master secret", randbytes )[0..47] + */ + if( handshake->resume == 0 ) + { + SSL_DEBUG_BUF( 3, "premaster secret", handshake->premaster, + handshake->pmslen ); + + handshake->tls_prf( handshake->premaster, handshake->pmslen, + "master secret", + handshake->randbytes, 64, session->master, 48 ); + + memset( handshake->premaster, 0, sizeof( handshake->premaster ) ); + } + else + SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) ); + + /* + * Swap the client and server random values. + */ + memcpy( tmp, handshake->randbytes, 64 ); + memcpy( handshake->randbytes, tmp + 32, 32 ); + memcpy( handshake->randbytes + 32, tmp, 32 ); + memset( tmp, 0, sizeof( tmp ) ); + + /* + * SSLv3: + * key block = + * MD5( master + SHA1( 'A' + master + randbytes ) ) + + * MD5( master + SHA1( 'BB' + master + randbytes ) ) + + * MD5( master + SHA1( 'CCC' + master + randbytes ) ) + + * MD5( master + SHA1( 'DDDD' + master + randbytes ) ) + + * ... + * + * TLSv1: + * key block = PRF( master, "key expansion", randbytes ) + */ + handshake->tls_prf( session->master, 48, "key expansion", + handshake->randbytes, 64, keyblk, 256 ); + + SSL_DEBUG_MSG( 3, ( "ciphersuite = %s", + ssl_get_ciphersuite_name( session->ciphersuite ) ) ); + SSL_DEBUG_BUF( 3, "master secret", session->master, 48 ); + SSL_DEBUG_BUF( 4, "random bytes", handshake->randbytes, 64 ); + SSL_DEBUG_BUF( 4, "key block", keyblk, 256 ); + + memset( handshake->randbytes, 0, sizeof( handshake->randbytes ) ); + + /* + * Determine the appropriate key, IV and MAC length. + */ + switch( session->ciphersuite ) + { +#if defined(POLARSSL_ARC4_C) + case TLS_RSA_WITH_RC4_128_MD5: + transform->keylen = 16; transform->minlen = 16; + transform->ivlen = 0; transform->maclen = 16; + break; + + case TLS_RSA_WITH_RC4_128_SHA: + transform->keylen = 16; transform->minlen = 20; + transform->ivlen = 0; transform->maclen = 20; + break; +#endif + +#if defined(POLARSSL_DES_C) + case TLS_RSA_WITH_3DES_EDE_CBC_SHA: + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + transform->keylen = 24; transform->minlen = 24; + transform->ivlen = 8; transform->maclen = 20; + break; +#endif + +#if defined(POLARSSL_AES_C) + case TLS_RSA_WITH_AES_128_CBC_SHA: + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + transform->keylen = 16; transform->minlen = 32; + transform->ivlen = 16; transform->maclen = 20; + break; + + case TLS_RSA_WITH_AES_256_CBC_SHA: + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + transform->keylen = 32; transform->minlen = 32; + transform->ivlen = 16; transform->maclen = 20; + break; + +#if defined(POLARSSL_SHA2_C) + case TLS_RSA_WITH_AES_128_CBC_SHA256: + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: + transform->keylen = 16; transform->minlen = 32; + transform->ivlen = 16; transform->maclen = 32; + break; + + case TLS_RSA_WITH_AES_256_CBC_SHA256: + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: + transform->keylen = 32; transform->minlen = 32; + transform->ivlen = 16; transform->maclen = 32; + break; +#endif +#if defined(POLARSSL_GCM_C) + case TLS_RSA_WITH_AES_128_GCM_SHA256: + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: + transform->keylen = 16; transform->minlen = 1; + transform->ivlen = 12; transform->maclen = 0; + transform->fixed_ivlen = 4; + break; + + case TLS_RSA_WITH_AES_256_GCM_SHA384: + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: + transform->keylen = 32; transform->minlen = 1; + transform->ivlen = 12; transform->maclen = 0; + transform->fixed_ivlen = 4; + break; +#endif +#endif + +#if defined(POLARSSL_CAMELLIA_C) + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: + transform->keylen = 16; transform->minlen = 32; + transform->ivlen = 16; transform->maclen = 20; + break; + + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: + transform->keylen = 32; transform->minlen = 32; + transform->ivlen = 16; transform->maclen = 20; + break; + +#if defined(POLARSSL_SHA2_C) + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + transform->keylen = 16; transform->minlen = 32; + transform->ivlen = 16; transform->maclen = 32; + break; + + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: + transform->keylen = 32; transform->minlen = 32; + transform->ivlen = 16; transform->maclen = 32; + break; +#endif +#endif + +#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) +#if defined(POLARSSL_CIPHER_NULL_CIPHER) + case TLS_RSA_WITH_NULL_MD5: + transform->keylen = 0; transform->minlen = 0; + transform->ivlen = 0; transform->maclen = 16; + break; + + case TLS_RSA_WITH_NULL_SHA: + transform->keylen = 0; transform->minlen = 0; + transform->ivlen = 0; transform->maclen = 20; + break; + + case TLS_RSA_WITH_NULL_SHA256: + transform->keylen = 0; transform->minlen = 0; + transform->ivlen = 0; transform->maclen = 32; + break; +#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ + +#if defined(POLARSSL_DES_C) + case TLS_RSA_WITH_DES_CBC_SHA: + case TLS_DHE_RSA_WITH_DES_CBC_SHA: + transform->keylen = 8; transform->minlen = 8; + transform->ivlen = 8; transform->maclen = 20; + break; +#endif +#endif /* defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) */ + + default: + SSL_DEBUG_MSG( 1, ( "ciphersuite %s is not available", + ssl_get_ciphersuite_name( session->ciphersuite ) ) ); + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + SSL_DEBUG_MSG( 3, ( "keylen: %d, minlen: %d, ivlen: %d, maclen: %d", + transform->keylen, transform->minlen, transform->ivlen, + transform->maclen ) ); + + /* + * Finally setup the cipher contexts, IVs and MAC secrets. + */ + if( ssl->endpoint == SSL_IS_CLIENT ) + { + key1 = keyblk + transform->maclen * 2; + key2 = keyblk + transform->maclen * 2 + transform->keylen; + + memcpy( transform->mac_enc, keyblk, transform->maclen ); + memcpy( transform->mac_dec, keyblk + transform->maclen, + transform->maclen ); + + /* + * This is not used in TLS v1.1. + */ + iv_copy_len = ( transform->fixed_ivlen ) ? + transform->fixed_ivlen : transform->ivlen; + memcpy( transform->iv_enc, key2 + transform->keylen, iv_copy_len ); + memcpy( transform->iv_dec, key2 + transform->keylen + iv_copy_len, + iv_copy_len ); + } + else + { + key1 = keyblk + transform->maclen * 2 + transform->keylen; + key2 = keyblk + transform->maclen * 2; + + memcpy( transform->mac_dec, keyblk, transform->maclen ); + memcpy( transform->mac_enc, keyblk + transform->maclen, + transform->maclen ); + + /* + * This is not used in TLS v1.1. + */ + iv_copy_len = ( transform->fixed_ivlen ) ? + transform->fixed_ivlen : transform->ivlen; + memcpy( transform->iv_dec, key1 + transform->keylen, iv_copy_len ); + memcpy( transform->iv_enc, key1 + transform->keylen + iv_copy_len, + iv_copy_len ); + } + +#if defined(POLARSSL_SSL_HW_RECORD_ACCEL) + if( ssl_hw_record_init != NULL) + { + int ret = 0; + + SSL_DEBUG_MSG( 2, ( "going for ssl_hw_record_init()" ) ); + + if( ( ret = ssl_hw_record_init( ssl, key1, key2, transform->iv_enc, + transform->iv_dec, transform->mac_enc, + transform->mac_dec ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_hw_record_init", ret ); + return POLARSSL_ERR_SSL_HW_ACCEL_FAILED; + } + } +#endif + + switch( session->ciphersuite ) + { +#if defined(POLARSSL_ARC4_C) + case TLS_RSA_WITH_RC4_128_MD5: + case TLS_RSA_WITH_RC4_128_SHA: + arc4_setup( (arc4_context *) transform->ctx_enc, key1, + transform->keylen ); + arc4_setup( (arc4_context *) transform->ctx_dec, key2, + transform->keylen ); + break; +#endif + +#if defined(POLARSSL_DES_C) + case TLS_RSA_WITH_3DES_EDE_CBC_SHA: + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + des3_set3key_enc( (des3_context *) transform->ctx_enc, key1 ); + des3_set3key_dec( (des3_context *) transform->ctx_dec, key2 ); + break; +#endif + +#if defined(POLARSSL_AES_C) + case TLS_RSA_WITH_AES_128_CBC_SHA: + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + case TLS_RSA_WITH_AES_128_CBC_SHA256: + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: + aes_setkey_enc( (aes_context *) transform->ctx_enc, key1, 128 ); + aes_setkey_dec( (aes_context *) transform->ctx_dec, key2, 128 ); + break; + + case TLS_RSA_WITH_AES_256_CBC_SHA: + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + case TLS_RSA_WITH_AES_256_CBC_SHA256: + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: + aes_setkey_enc( (aes_context *) transform->ctx_enc, key1, 256 ); + aes_setkey_dec( (aes_context *) transform->ctx_dec, key2, 256 ); + break; + +#if defined(POLARSSL_GCM_C) + case TLS_RSA_WITH_AES_128_GCM_SHA256: + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: + gcm_init( (gcm_context *) transform->ctx_enc, key1, 128 ); + gcm_init( (gcm_context *) transform->ctx_dec, key2, 128 ); + break; + + case TLS_RSA_WITH_AES_256_GCM_SHA384: + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: + gcm_init( (gcm_context *) transform->ctx_enc, key1, 256 ); + gcm_init( (gcm_context *) transform->ctx_dec, key2, 256 ); + break; +#endif +#endif + +#if defined(POLARSSL_CAMELLIA_C) + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256: + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + camellia_setkey_enc( (camellia_context *) transform->ctx_enc, key1, 128 ); + camellia_setkey_dec( (camellia_context *) transform->ctx_dec, key2, 128 ); + break; + + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: + camellia_setkey_enc( (camellia_context *) transform->ctx_enc, key1, 256 ); + camellia_setkey_dec( (camellia_context *) transform->ctx_dec, key2, 256 ); + break; +#endif + +#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) +#if defined(POLARSSL_CIPHER_NULL_CIPHER) + case TLS_RSA_WITH_NULL_MD5: + case TLS_RSA_WITH_NULL_SHA: + case TLS_RSA_WITH_NULL_SHA256: + break; +#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ + +#if defined(POLARSSL_DES_C) + case TLS_RSA_WITH_DES_CBC_SHA: + case TLS_DHE_RSA_WITH_DES_CBC_SHA: + des_setkey_enc( (des_context *) transform->ctx_enc, key1 ); + des_setkey_dec( (des_context *) transform->ctx_dec, key2 ); + break; +#endif +#endif /* defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) */ + + default: + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + memset( keyblk, 0, sizeof( keyblk ) ); + +#if defined(POLARSSL_ZLIB_SUPPORT) + // Initialize compression + // + if( session->compression == SSL_COMPRESS_DEFLATE ) + { + SSL_DEBUG_MSG( 3, ( "Initializing zlib states" ) ); + + memset( &transform->ctx_deflate, 0, sizeof( transform->ctx_deflate ) ); + memset( &transform->ctx_inflate, 0, sizeof( transform->ctx_inflate ) ); + + if( deflateInit( &transform->ctx_deflate, Z_DEFAULT_COMPRESSION ) != Z_OK || + inflateInit( &transform->ctx_inflate ) != Z_OK ) + { + SSL_DEBUG_MSG( 1, ( "Failed to initialize compression" ) ); + return( POLARSSL_ERR_SSL_COMPRESSION_FAILED ); + } + } +#endif /* POLARSSL_ZLIB_SUPPORT */ + + SSL_DEBUG_MSG( 2, ( "<= derive keys" ) ); + + return( 0 ); +} + +void ssl_calc_verify_ssl( ssl_context *ssl, unsigned char hash[36] ) +{ + md5_context md5; + sha1_context sha1; + unsigned char pad_1[48]; + unsigned char pad_2[48]; + + SSL_DEBUG_MSG( 2, ( "=> calc verify ssl" ) ); + + memcpy( &md5 , &ssl->handshake->fin_md5 , sizeof(md5_context) ); + memcpy( &sha1, &ssl->handshake->fin_sha1, sizeof(sha1_context) ); + + memset( pad_1, 0x36, 48 ); + memset( pad_2, 0x5C, 48 ); + + md5_update( &md5, ssl->session_negotiate->master, 48 ); + md5_update( &md5, pad_1, 48 ); + md5_finish( &md5, hash ); + + md5_starts( &md5 ); + md5_update( &md5, ssl->session_negotiate->master, 48 ); + md5_update( &md5, pad_2, 48 ); + md5_update( &md5, hash, 16 ); + md5_finish( &md5, hash ); + + sha1_update( &sha1, ssl->session_negotiate->master, 48 ); + sha1_update( &sha1, pad_1, 40 ); + sha1_finish( &sha1, hash + 16 ); + + sha1_starts( &sha1 ); + sha1_update( &sha1, ssl->session_negotiate->master, 48 ); + sha1_update( &sha1, pad_2, 40 ); + sha1_update( &sha1, hash + 16, 20 ); + sha1_finish( &sha1, hash + 16 ); + + SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 ); + SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + return; +} + +void ssl_calc_verify_tls( ssl_context *ssl, unsigned char hash[36] ) +{ + md5_context md5; + sha1_context sha1; + + SSL_DEBUG_MSG( 2, ( "=> calc verify tls" ) ); + + memcpy( &md5 , &ssl->handshake->fin_md5 , sizeof(md5_context) ); + memcpy( &sha1, &ssl->handshake->fin_sha1, sizeof(sha1_context) ); + + md5_finish( &md5, hash ); + sha1_finish( &sha1, hash + 16 ); + + SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 ); + SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + return; +} + +void ssl_calc_verify_tls_sha256( ssl_context *ssl, unsigned char hash[32] ) +{ + sha2_context sha2; + + SSL_DEBUG_MSG( 2, ( "=> calc verify sha256" ) ); + + memcpy( &sha2, &ssl->handshake->fin_sha2, sizeof(sha2_context) ); + sha2_finish( &sha2, hash ); + + SSL_DEBUG_BUF( 3, "calculated verify result", hash, 32 ); + SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + return; +} + +#if defined(POLARSSL_SHA4_C) +void ssl_calc_verify_tls_sha384( ssl_context *ssl, unsigned char hash[48] ) +{ + sha4_context sha4; + + SSL_DEBUG_MSG( 2, ( "=> calc verify sha384" ) ); + + memcpy( &sha4, &ssl->handshake->fin_sha4, sizeof(sha4_context) ); + sha4_finish( &sha4, hash ); + + SSL_DEBUG_BUF( 3, "calculated verify result", hash, 48 ); + SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + return; +} +#endif + +/* + * SSLv3.0 MAC functions + */ +static void ssl_mac_md5( unsigned char *secret, + unsigned char *buf, size_t len, + unsigned char *ctr, int type ) +{ + unsigned char header[11]; + unsigned char padding[48]; + md5_context md5; + + memcpy( header, ctr, 8 ); + header[ 8] = (unsigned char) type; + header[ 9] = (unsigned char)( len >> 8 ); + header[10] = (unsigned char)( len ); + + memset( padding, 0x36, 48 ); + md5_starts( &md5 ); + md5_update( &md5, secret, 16 ); + md5_update( &md5, padding, 48 ); + md5_update( &md5, header, 11 ); + md5_update( &md5, buf, len ); + md5_finish( &md5, buf + len ); + + memset( padding, 0x5C, 48 ); + md5_starts( &md5 ); + md5_update( &md5, secret, 16 ); + md5_update( &md5, padding, 48 ); + md5_update( &md5, buf + len, 16 ); + md5_finish( &md5, buf + len ); +} + +static void ssl_mac_sha1( unsigned char *secret, + unsigned char *buf, size_t len, + unsigned char *ctr, int type ) +{ + unsigned char header[11]; + unsigned char padding[40]; + sha1_context sha1; + + memcpy( header, ctr, 8 ); + header[ 8] = (unsigned char) type; + header[ 9] = (unsigned char)( len >> 8 ); + header[10] = (unsigned char)( len ); + + memset( padding, 0x36, 40 ); + sha1_starts( &sha1 ); + sha1_update( &sha1, secret, 20 ); + sha1_update( &sha1, padding, 40 ); + sha1_update( &sha1, header, 11 ); + sha1_update( &sha1, buf, len ); + sha1_finish( &sha1, buf + len ); + + memset( padding, 0x5C, 40 ); + sha1_starts( &sha1 ); + sha1_update( &sha1, secret, 20 ); + sha1_update( &sha1, padding, 40 ); + sha1_update( &sha1, buf + len, 20 ); + sha1_finish( &sha1, buf + len ); +} + +static void ssl_mac_sha2( unsigned char *secret, + unsigned char *buf, size_t len, + unsigned char *ctr, int type ) +{ + unsigned char header[11]; + unsigned char padding[32]; + sha2_context sha2; + + memcpy( header, ctr, 8 ); + header[ 8] = (unsigned char) type; + header[ 9] = (unsigned char)( len >> 8 ); + header[10] = (unsigned char)( len ); + + memset( padding, 0x36, 32 ); + sha2_starts( &sha2, 0 ); + sha2_update( &sha2, secret, 32 ); + sha2_update( &sha2, padding, 32 ); + sha2_update( &sha2, header, 11 ); + sha2_update( &sha2, buf, len ); + sha2_finish( &sha2, buf + len ); + + memset( padding, 0x5C, 32 ); + sha2_starts( &sha2, 0 ); + sha2_update( &sha2, secret, 32 ); + sha2_update( &sha2, padding, 32 ); + sha2_update( &sha2, buf + len, 32 ); + sha2_finish( &sha2, buf + len ); +} + +/* + * Encryption/decryption functions + */ +static int ssl_encrypt_buf( ssl_context *ssl ) +{ + size_t i, padlen; + + SSL_DEBUG_MSG( 2, ( "=> encrypt buf" ) ); + + /* + * Add MAC then encrypt + */ + if( ssl->minor_ver == SSL_MINOR_VERSION_0 ) + { + if( ssl->transform_out->maclen == 16 ) + ssl_mac_md5( ssl->transform_out->mac_enc, + ssl->out_msg, ssl->out_msglen, + ssl->out_ctr, ssl->out_msgtype ); + else if( ssl->transform_out->maclen == 20 ) + ssl_mac_sha1( ssl->transform_out->mac_enc, + ssl->out_msg, ssl->out_msglen, + ssl->out_ctr, ssl->out_msgtype ); + else if( ssl->transform_out->maclen == 32 ) + ssl_mac_sha2( ssl->transform_out->mac_enc, + ssl->out_msg, ssl->out_msglen, + ssl->out_ctr, ssl->out_msgtype ); + else if( ssl->transform_out->maclen != 0 ) + { + SSL_DEBUG_MSG( 1, ( "invalid MAC len: %d", + ssl->transform_out->maclen ) ); + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); + } + } + else + { + if( ssl->transform_out->maclen == 16 ) + { + md5_context ctx; + md5_hmac_starts( &ctx, ssl->transform_out->mac_enc, 16 ); + md5_hmac_update( &ctx, ssl->out_ctr, 13 ); + md5_hmac_update( &ctx, ssl->out_msg, ssl->out_msglen ); + md5_hmac_finish( &ctx, ssl->out_msg + ssl->out_msglen ); + memset( &ctx, 0, sizeof(md5_context)); + } + else if( ssl->transform_out->maclen == 20 ) + { + sha1_context ctx; + sha1_hmac_starts( &ctx, ssl->transform_out->mac_enc, 20 ); + sha1_hmac_update( &ctx, ssl->out_ctr, 13 ); + sha1_hmac_update( &ctx, ssl->out_msg, ssl->out_msglen ); + sha1_hmac_finish( &ctx, ssl->out_msg + ssl->out_msglen ); + memset( &ctx, 0, sizeof(sha1_context)); + } + else if( ssl->transform_out->maclen == 32 ) + { + sha2_context ctx; + sha2_hmac_starts( &ctx, ssl->transform_out->mac_enc, 32, 0 ); + sha2_hmac_update( &ctx, ssl->out_ctr, 13 ); + sha2_hmac_update( &ctx, ssl->out_msg, ssl->out_msglen ); + sha2_hmac_finish( &ctx, ssl->out_msg + ssl->out_msglen ); + memset( &ctx, 0, sizeof(sha2_context)); + } + else if( ssl->transform_out->maclen != 0 ) + { + SSL_DEBUG_MSG( 1, ( "invalid MAC len: %d", + ssl->transform_out->maclen ) ); + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); + } + } + + SSL_DEBUG_BUF( 4, "computed mac", + ssl->out_msg + ssl->out_msglen, ssl->transform_out->maclen ); + + ssl->out_msglen += ssl->transform_out->maclen; + + if( ssl->transform_out->ivlen == 0 ) + { + padlen = 0; + + SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of padding", + ssl->out_msglen, 0 ) ); + + SSL_DEBUG_BUF( 4, "before encrypt: output payload", + ssl->out_msg, ssl->out_msglen ); + +#if defined(POLARSSL_ARC4_C) + if( ssl->session_out->ciphersuite == TLS_RSA_WITH_RC4_128_MD5 || + ssl->session_out->ciphersuite == TLS_RSA_WITH_RC4_128_SHA ) + { + arc4_crypt( (arc4_context *) ssl->transform_out->ctx_enc, + ssl->out_msglen, ssl->out_msg, + ssl->out_msg ); + } else +#endif +#if defined(POLARSSL_CIPHER_NULL_CIPHER) + if( ssl->session_out->ciphersuite == TLS_RSA_WITH_NULL_MD5 || + ssl->session_out->ciphersuite == TLS_RSA_WITH_NULL_SHA || + ssl->session_out->ciphersuite == TLS_RSA_WITH_NULL_SHA256 ) + { + } else +#endif + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); + } + else if( ssl->transform_out->ivlen == 12 ) + { + size_t enc_msglen; + unsigned char *enc_msg; + unsigned char add_data[13]; + int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE; + + padlen = 0; + enc_msglen = ssl->out_msglen; + + memcpy( add_data, ssl->out_ctr, 8 ); + add_data[8] = ssl->out_msgtype; + add_data[9] = ssl->major_ver; + add_data[10] = ssl->minor_ver; + add_data[11] = ( ssl->out_msglen >> 8 ) & 0xFF; + add_data[12] = ssl->out_msglen & 0xFF; + + SSL_DEBUG_BUF( 4, "additional data used for AEAD", + add_data, 13 ); + +#if defined(POLARSSL_AES_C) && defined(POLARSSL_GCM_C) + + if( ssl->session_out->ciphersuite == TLS_RSA_WITH_AES_128_GCM_SHA256 || + ssl->session_out->ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 || + ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 || + ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ) + { + /* + * Generate IV + */ + ret = ssl->f_rng( ssl->p_rng, + ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen, + ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen ); + if( ret != 0 ) + return( ret ); + + /* + * Shift message for ivlen bytes and prepend IV + */ + memmove( ssl->out_msg + ssl->transform_out->ivlen - + ssl->transform_out->fixed_ivlen, + ssl->out_msg, ssl->out_msglen ); + memcpy( ssl->out_msg, + ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen, + ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen ); + + /* + * Fix pointer positions and message length with added IV + */ + enc_msg = ssl->out_msg + ssl->transform_out->ivlen - + ssl->transform_out->fixed_ivlen; + enc_msglen = ssl->out_msglen; + ssl->out_msglen += ssl->transform_out->ivlen - + ssl->transform_out->fixed_ivlen; + + SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of padding", + ssl->out_msglen, 0 ) ); + + SSL_DEBUG_BUF( 4, "before encrypt: output payload", + ssl->out_msg, ssl->out_msglen ); + + /* + * Adjust for tag + */ + ssl->out_msglen += 16; + + gcm_crypt_and_tag( (gcm_context *) ssl->transform_out->ctx_enc, + GCM_ENCRYPT, enc_msglen, + ssl->transform_out->iv_enc, ssl->transform_out->ivlen, + add_data, 13, + enc_msg, enc_msg, + 16, enc_msg + enc_msglen ); + + SSL_DEBUG_BUF( 4, "after encrypt: tag", + enc_msg + enc_msglen, 16 ); + + } else +#endif + return( ret ); + } + else + { + unsigned char *enc_msg; + size_t enc_msglen; + + padlen = ssl->transform_out->ivlen - ( ssl->out_msglen + 1 ) % + ssl->transform_out->ivlen; + if( padlen == ssl->transform_out->ivlen ) + padlen = 0; + + for( i = 0; i <= padlen; i++ ) + ssl->out_msg[ssl->out_msglen + i] = (unsigned char) padlen; + + ssl->out_msglen += padlen + 1; + + enc_msglen = ssl->out_msglen; + enc_msg = ssl->out_msg; + + /* + * Prepend per-record IV for block cipher in TLS v1.1 and up as per + * Method 1 (6.2.3.2. in RFC4346 and RFC5246) + */ + if( ssl->minor_ver >= SSL_MINOR_VERSION_2 ) + { + /* + * Generate IV + */ + int ret = ssl->f_rng( ssl->p_rng, ssl->transform_out->iv_enc, + ssl->transform_out->ivlen ); + if( ret != 0 ) + return( ret ); + + /* + * Shift message for ivlen bytes and prepend IV + */ + memmove( ssl->out_msg + ssl->transform_out->ivlen, ssl->out_msg, + ssl->out_msglen ); + memcpy( ssl->out_msg, ssl->transform_out->iv_enc, + ssl->transform_out->ivlen ); + + /* + * Fix pointer positions and message length with added IV + */ + enc_msg = ssl->out_msg + ssl->transform_out->ivlen; + enc_msglen = ssl->out_msglen; + ssl->out_msglen += ssl->transform_out->ivlen; + } + + SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of IV and %d bytes of padding", + ssl->out_msglen, ssl->transform_out->ivlen, padlen + 1 ) ); + + SSL_DEBUG_BUF( 4, "before encrypt: output payload", + ssl->out_msg, ssl->out_msglen ); + + switch( ssl->transform_out->ivlen ) + { +#if defined(POLARSSL_DES_C) + case 8: +#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) + if( ssl->session_out->ciphersuite == TLS_RSA_WITH_DES_CBC_SHA || + ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_DES_CBC_SHA ) + { + des_crypt_cbc( (des_context *) ssl->transform_out->ctx_enc, + DES_ENCRYPT, enc_msglen, + ssl->transform_out->iv_enc, enc_msg, enc_msg ); + } + else +#endif + des3_crypt_cbc( (des3_context *) ssl->transform_out->ctx_enc, + DES_ENCRYPT, enc_msglen, + ssl->transform_out->iv_enc, enc_msg, enc_msg ); + break; +#endif + + case 16: +#if defined(POLARSSL_AES_C) + if ( ssl->session_out->ciphersuite == TLS_RSA_WITH_AES_128_CBC_SHA || + ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA || + ssl->session_out->ciphersuite == TLS_RSA_WITH_AES_256_CBC_SHA || + ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA || + ssl->session_out->ciphersuite == TLS_RSA_WITH_AES_128_CBC_SHA256 || + ssl->session_out->ciphersuite == TLS_RSA_WITH_AES_256_CBC_SHA256 || + ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 || + ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ) + { + aes_crypt_cbc( (aes_context *) ssl->transform_out->ctx_enc, + AES_ENCRYPT, enc_msglen, + ssl->transform_out->iv_enc, enc_msg, enc_msg); + break; + } +#endif + +#if defined(POLARSSL_CAMELLIA_C) + if ( ssl->session_out->ciphersuite == TLS_RSA_WITH_CAMELLIA_128_CBC_SHA || + ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA || + ssl->session_out->ciphersuite == TLS_RSA_WITH_CAMELLIA_256_CBC_SHA || + ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA || + ssl->session_out->ciphersuite == TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 || + ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 || + ssl->session_out->ciphersuite == TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 || + ssl->session_out->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 ) + { + camellia_crypt_cbc( (camellia_context *) ssl->transform_out->ctx_enc, + CAMELLIA_ENCRYPT, enc_msglen, + ssl->transform_out->iv_enc, enc_msg, enc_msg ); + break; + } +#endif + + default: + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); + } + } + + for( i = 8; i > 0; i-- ) + if( ++ssl->out_ctr[i - 1] != 0 ) + break; + + SSL_DEBUG_MSG( 2, ( "<= encrypt buf" ) ); + + return( 0 ); +} + +/* + * TODO: Use digest version when integrated! + */ +#define POLARSSL_SSL_MAX_MAC_SIZE 32 + +static int ssl_decrypt_buf( ssl_context *ssl ) +{ + size_t i, padlen = 0, correct = 1; + unsigned char tmp[POLARSSL_SSL_MAX_MAC_SIZE]; + + SSL_DEBUG_MSG( 2, ( "=> decrypt buf" ) ); + + if( ssl->in_msglen < ssl->transform_in->minlen ) + { + SSL_DEBUG_MSG( 1, ( "in_msglen (%d) < minlen (%d)", + ssl->in_msglen, ssl->transform_in->minlen ) ); + return( POLARSSL_ERR_SSL_INVALID_MAC ); + } + + if( ssl->transform_in->ivlen == 0 ) + { +#if defined(POLARSSL_ARC4_C) + if( ssl->session_in->ciphersuite == TLS_RSA_WITH_RC4_128_MD5 || + ssl->session_in->ciphersuite == TLS_RSA_WITH_RC4_128_SHA ) + { + arc4_crypt( (arc4_context *) ssl->transform_in->ctx_dec, + ssl->in_msglen, ssl->in_msg, + ssl->in_msg ); + } else +#endif +#if defined(POLARSSL_CIPHER_NULL_CIPHER) + if( ssl->session_in->ciphersuite == TLS_RSA_WITH_NULL_MD5 || + ssl->session_in->ciphersuite == TLS_RSA_WITH_NULL_SHA || + ssl->session_in->ciphersuite == TLS_RSA_WITH_NULL_SHA256 ) + { + } else +#endif + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); + } + else if( ssl->transform_in->ivlen == 12 ) + { + unsigned char *dec_msg; + unsigned char *dec_msg_result; + size_t dec_msglen; + unsigned char add_data[13]; + int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE; + +#if defined(POLARSSL_AES_C) && defined(POLARSSL_GCM_C) + if( ssl->session_in->ciphersuite == TLS_RSA_WITH_AES_128_GCM_SHA256 || + ssl->session_in->ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 || + ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 || + ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ) + { + dec_msglen = ssl->in_msglen - ( ssl->transform_in->ivlen - + ssl->transform_in->fixed_ivlen ); + dec_msglen -= 16; + dec_msg = ssl->in_msg + ( ssl->transform_in->ivlen - + ssl->transform_in->fixed_ivlen ); + dec_msg_result = ssl->in_msg; + ssl->in_msglen = dec_msglen; + + memcpy( add_data, ssl->in_ctr, 8 ); + add_data[8] = ssl->in_msgtype; + add_data[9] = ssl->major_ver; + add_data[10] = ssl->minor_ver; + add_data[11] = ( ssl->in_msglen >> 8 ) & 0xFF; + add_data[12] = ssl->in_msglen & 0xFF; + + SSL_DEBUG_BUF( 4, "additional data used for AEAD", + add_data, 13 ); + + memcpy( ssl->transform_in->iv_dec + ssl->transform_in->fixed_ivlen, + ssl->in_msg, + ssl->transform_in->ivlen - ssl->transform_in->fixed_ivlen ); + + SSL_DEBUG_BUF( 4, "IV used", ssl->transform_in->iv_dec, + ssl->transform_in->ivlen ); + SSL_DEBUG_BUF( 4, "TAG used", dec_msg + dec_msglen, 16 ); + + memcpy( ssl->transform_in->iv_dec + ssl->transform_in->fixed_ivlen, + ssl->in_msg, + ssl->transform_in->ivlen - ssl->transform_in->fixed_ivlen ); + + ret = gcm_auth_decrypt( (gcm_context *) ssl->transform_in->ctx_dec, + dec_msglen, + ssl->transform_in->iv_dec, + ssl->transform_in->ivlen, + add_data, 13, + dec_msg + dec_msglen, 16, + dec_msg, dec_msg_result ); + + if( ret != 0 ) + { + SSL_DEBUG_MSG( 1, ( "AEAD decrypt failed on validation (ret = -0x%02x)", + -ret ) ); + + return( POLARSSL_ERR_SSL_INVALID_MAC ); + } + } else +#endif + return( ret ); + } + else + { + /* + * Decrypt and check the padding + */ + unsigned char *dec_msg; + unsigned char *dec_msg_result; + size_t dec_msglen; + size_t minlen = 0; + + /* + * Check immediate ciphertext sanity + */ + if( ssl->in_msglen % ssl->transform_in->ivlen != 0 ) + { + SSL_DEBUG_MSG( 1, ( "msglen (%d) %% ivlen (%d) != 0", + ssl->in_msglen, ssl->transform_in->ivlen ) ); + return( POLARSSL_ERR_SSL_INVALID_MAC ); + } + + if( ssl->minor_ver >= SSL_MINOR_VERSION_2 ) + minlen += ssl->transform_in->ivlen; + + if( ssl->in_msglen < minlen + ssl->transform_in->ivlen || + ssl->in_msglen < minlen + ssl->transform_in->maclen + 1 ) + { + SSL_DEBUG_MSG( 1, ( "msglen (%d) < max( ivlen(%d), maclen (%d) + 1 ) ( + expl IV )", + ssl->in_msglen, ssl->transform_in->ivlen, ssl->transform_in->maclen ) ); + return( POLARSSL_ERR_SSL_INVALID_MAC ); + } + + dec_msglen = ssl->in_msglen; + dec_msg = ssl->in_msg; + dec_msg_result = ssl->in_msg; + + /* + * Initialize for prepended IV for block cipher in TLS v1.1 and up + */ + if( ssl->minor_ver >= SSL_MINOR_VERSION_2 ) + { + dec_msg += ssl->transform_in->ivlen; + dec_msglen -= ssl->transform_in->ivlen; + ssl->in_msglen -= ssl->transform_in->ivlen; + + for( i = 0; i < ssl->transform_in->ivlen; i++ ) + ssl->transform_in->iv_dec[i] = ssl->in_msg[i]; + } + + switch( ssl->transform_in->ivlen ) + { +#if defined(POLARSSL_DES_C) + case 8: +#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) + if( ssl->session_in->ciphersuite == TLS_RSA_WITH_DES_CBC_SHA || + ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_DES_CBC_SHA ) + { + des_crypt_cbc( (des_context *) ssl->transform_in->ctx_dec, + DES_DECRYPT, dec_msglen, + ssl->transform_in->iv_dec, dec_msg, dec_msg_result ); + } + else +#endif + des3_crypt_cbc( (des3_context *) ssl->transform_in->ctx_dec, + DES_DECRYPT, dec_msglen, + ssl->transform_in->iv_dec, dec_msg, dec_msg_result ); + break; +#endif + + case 16: +#if defined(POLARSSL_AES_C) + if ( ssl->session_in->ciphersuite == TLS_RSA_WITH_AES_128_CBC_SHA || + ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA || + ssl->session_in->ciphersuite == TLS_RSA_WITH_AES_256_CBC_SHA || + ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA || + ssl->session_in->ciphersuite == TLS_RSA_WITH_AES_128_CBC_SHA256 || + ssl->session_in->ciphersuite == TLS_RSA_WITH_AES_256_CBC_SHA256 || + ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 || + ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ) + { + aes_crypt_cbc( (aes_context *) ssl->transform_in->ctx_dec, + AES_DECRYPT, dec_msglen, + ssl->transform_in->iv_dec, dec_msg, dec_msg_result ); + break; + } +#endif + +#if defined(POLARSSL_CAMELLIA_C) + if ( ssl->session_in->ciphersuite == TLS_RSA_WITH_CAMELLIA_128_CBC_SHA || + ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA || + ssl->session_in->ciphersuite == TLS_RSA_WITH_CAMELLIA_256_CBC_SHA || + ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA || + ssl->session_in->ciphersuite == TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 || + ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 || + ssl->session_in->ciphersuite == TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 || + ssl->session_in->ciphersuite == TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 ) + { + camellia_crypt_cbc( (camellia_context *) ssl->transform_in->ctx_dec, + CAMELLIA_DECRYPT, dec_msglen, + ssl->transform_in->iv_dec, dec_msg, dec_msg_result ); + break; + } +#endif + + default: + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + padlen = 1 + ssl->in_msg[ssl->in_msglen - 1]; + + if( ssl->in_msglen < ssl->transform_in->maclen + padlen ) + { +#if defined(POLARSSL_SSL_DEBUG_ALL) + SSL_DEBUG_MSG( 1, ( "msglen (%d) < maclen (%d) + padlen (%d)", + ssl->in_msglen, ssl->transform_in->maclen, padlen ) ); +#endif + padlen = 0; + correct = 0; + } + + if( ssl->minor_ver == SSL_MINOR_VERSION_0 ) + { + if( padlen > ssl->transform_in->ivlen ) + { +#if defined(POLARSSL_SSL_DEBUG_ALL) + SSL_DEBUG_MSG( 1, ( "bad padding length: is %d, " + "should be no more than %d", + padlen, ssl->transform_in->ivlen ) ); +#endif + correct = 0; + } + } + else + { + /* + * TLSv1+: always check the padding up to the first failure + * and fake check up to 256 bytes of padding + */ + size_t pad_count = 0, fake_pad_count = 0; + size_t padding_idx = ssl->in_msglen - padlen - 1; + + for( i = 1; i <= padlen; i++ ) + pad_count += ( ssl->in_msg[padding_idx + i] == padlen - 1 ); + + for( ; i <= 256; i++ ) + fake_pad_count += ( ssl->in_msg[padding_idx + i] == padlen - 1 ); + + correct &= ( pad_count == padlen ); /* Only 1 on correct padding */ + correct &= ( pad_count + fake_pad_count < 512 ); /* Always 1 */ + +#if defined(POLARSSL_SSL_DEBUG_ALL) + if( padlen > 0 && correct == 0) + SSL_DEBUG_MSG( 1, ( "bad padding byte detected" ) ); +#endif + padlen &= correct * 0x1FF; + } + } + + SSL_DEBUG_BUF( 4, "raw buffer after decryption", + ssl->in_msg, ssl->in_msglen ); + + /* + * Always compute the MAC (RFC4346, CBCTIME). + */ + ssl->in_msglen -= ( ssl->transform_in->maclen + padlen ); + + ssl->in_hdr[3] = (unsigned char)( ssl->in_msglen >> 8 ); + ssl->in_hdr[4] = (unsigned char)( ssl->in_msglen ); + + memcpy( tmp, ssl->in_msg + ssl->in_msglen, ssl->transform_in->maclen ); + + if( ssl->minor_ver == SSL_MINOR_VERSION_0 ) + { + if( ssl->transform_in->maclen == 16 ) + ssl_mac_md5( ssl->transform_in->mac_dec, + ssl->in_msg, ssl->in_msglen, + ssl->in_ctr, ssl->in_msgtype ); + else if( ssl->transform_in->maclen == 20 ) + ssl_mac_sha1( ssl->transform_in->mac_dec, + ssl->in_msg, ssl->in_msglen, + ssl->in_ctr, ssl->in_msgtype ); + else if( ssl->transform_in->maclen == 32 ) + ssl_mac_sha2( ssl->transform_in->mac_dec, + ssl->in_msg, ssl->in_msglen, + ssl->in_ctr, ssl->in_msgtype ); + else if( ssl->transform_in->maclen != 0 ) + { + SSL_DEBUG_MSG( 1, ( "invalid MAC len: %d", + ssl->transform_in->maclen ) ); + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); + } + } + else + { + /* + * Process MAC and always update for padlen afterwards to make + * total time independent of padlen + * + * extra_run compensates MAC check for padlen + * + * Known timing attacks: + * - Lucky Thirteen (http://www.isg.rhul.ac.uk/tls/TLStiming.pdf) + * + * We use ( ( Lx + 8 ) / 64 ) to handle 'negative Lx' values + * correctly. (We round down instead of up, so -56 is the correct + * value for our calculations instead of -55) + */ + int j, extra_run = 0; + extra_run = ( 13 + ssl->in_msglen + padlen + 8 ) / 64 - + ( 13 + ssl->in_msglen + 8 ) / 64; + + extra_run &= correct * 0xFF; + + if( ssl->transform_in->maclen == 16 ) + { + md5_context ctx; + md5_hmac_starts( &ctx, ssl->transform_in->mac_dec, 16 ); + md5_hmac_update( &ctx, ssl->in_ctr, ssl->in_msglen + 13 ); + md5_hmac_finish( &ctx, ssl->in_msg + ssl->in_msglen ); + + for( j = 0; j < extra_run; j++ ) + md5_process( &ctx, ssl->in_msg ); + } + else if( ssl->transform_in->maclen == 20 ) + { + sha1_context ctx; + sha1_hmac_starts( &ctx, ssl->transform_in->mac_dec, 20 ); + sha1_hmac_update( &ctx, ssl->in_ctr, ssl->in_msglen + 13 ); + sha1_hmac_finish( &ctx, ssl->in_msg + ssl->in_msglen ); + + for( j = 0; j < extra_run; j++ ) + sha1_process( &ctx, ssl->in_msg ); + } + else if( ssl->transform_in->maclen == 32 ) + { + sha2_context ctx; + sha2_hmac_starts( &ctx, ssl->transform_in->mac_dec, 32, 0 ); + sha2_hmac_update( &ctx, ssl->in_ctr, ssl->in_msglen + 13 ); + sha2_hmac_finish( &ctx, ssl->in_msg + ssl->in_msglen ); + + for( j = 0; j < extra_run; j++ ) + sha2_process( &ctx, ssl->in_msg ); + } + else if( ssl->transform_in->maclen != 0 ) + { + SSL_DEBUG_MSG( 1, ( "invalid MAC len: %d", + ssl->transform_in->maclen ) ); + return( POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE ); + } + } + + SSL_DEBUG_BUF( 4, "message mac", tmp, ssl->transform_in->maclen ); + SSL_DEBUG_BUF( 4, "computed mac", ssl->in_msg + ssl->in_msglen, + ssl->transform_in->maclen ); + + if( memcmp( tmp, ssl->in_msg + ssl->in_msglen, + ssl->transform_in->maclen ) != 0 ) + { +#if defined(POLARSSL_SSL_DEBUG_ALL) + SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); +#endif + correct = 0; + } + + /* + * Finally check the correct flag + */ + if( correct == 0 ) + return( POLARSSL_ERR_SSL_INVALID_MAC ); + + if( ssl->in_msglen == 0 ) + { + ssl->nb_zero++; + + /* + * Three or more empty messages may be a DoS attack + * (excessive CPU consumption). + */ + if( ssl->nb_zero > 3 ) + { + SSL_DEBUG_MSG( 1, ( "received four consecutive empty " + "messages, possible DoS attack" ) ); + return( POLARSSL_ERR_SSL_INVALID_MAC ); + } + } + else + ssl->nb_zero = 0; + + for( i = 8; i > 0; i-- ) + if( ++ssl->in_ctr[i - 1] != 0 ) + break; + + SSL_DEBUG_MSG( 2, ( "<= decrypt buf" ) ); + + return( 0 ); +} + +#if defined(POLARSSL_ZLIB_SUPPORT) +/* + * Compression/decompression functions + */ +static int ssl_compress_buf( ssl_context *ssl ) +{ + int ret; + unsigned char *msg_post = ssl->out_msg; + size_t len_pre = ssl->out_msglen; + unsigned char *msg_pre; + + SSL_DEBUG_MSG( 2, ( "=> compress buf" ) ); + + msg_pre = (unsigned char*) malloc( len_pre ); + if( msg_pre == NULL ) + { + SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len_pre ) ); + return( POLARSSL_ERR_SSL_MALLOC_FAILED ); + } + + memcpy( msg_pre, ssl->out_msg, len_pre ); + + SSL_DEBUG_MSG( 3, ( "before compression: msglen = %d, ", + ssl->out_msglen ) ); + + SSL_DEBUG_BUF( 4, "before compression: output payload", + ssl->out_msg, ssl->out_msglen ); + + ssl->transform_out->ctx_deflate.next_in = msg_pre; + ssl->transform_out->ctx_deflate.avail_in = len_pre; + ssl->transform_out->ctx_deflate.next_out = msg_post; + ssl->transform_out->ctx_deflate.avail_out = SSL_BUFFER_LEN; + + ret = deflate( &ssl->transform_out->ctx_deflate, Z_SYNC_FLUSH ); + if( ret != Z_OK ) + { + SSL_DEBUG_MSG( 1, ( "failed to perform compression (%d)", ret ) ); + return( POLARSSL_ERR_SSL_COMPRESSION_FAILED ); + } + + ssl->out_msglen = SSL_BUFFER_LEN - ssl->transform_out->ctx_deflate.avail_out; + + free( msg_pre ); + + SSL_DEBUG_MSG( 3, ( "after compression: msglen = %d, ", + ssl->out_msglen ) ); + + SSL_DEBUG_BUF( 4, "after compression: output payload", + ssl->out_msg, ssl->out_msglen ); + + SSL_DEBUG_MSG( 2, ( "<= compress buf" ) ); + + return( 0 ); +} + +static int ssl_decompress_buf( ssl_context *ssl ) +{ + int ret; + unsigned char *msg_post = ssl->in_msg; + size_t len_pre = ssl->in_msglen; + unsigned char *msg_pre; + + SSL_DEBUG_MSG( 2, ( "=> decompress buf" ) ); + + msg_pre = (unsigned char*) malloc( len_pre ); + if( msg_pre == NULL ) + { + SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len_pre ) ); + return( POLARSSL_ERR_SSL_MALLOC_FAILED ); + } + + memcpy( msg_pre, ssl->in_msg, len_pre ); + + SSL_DEBUG_MSG( 3, ( "before decompression: msglen = %d, ", + ssl->in_msglen ) ); + + SSL_DEBUG_BUF( 4, "before decompression: input payload", + ssl->in_msg, ssl->in_msglen ); + + ssl->transform_in->ctx_inflate.next_in = msg_pre; + ssl->transform_in->ctx_inflate.avail_in = len_pre; + ssl->transform_in->ctx_inflate.next_out = msg_post; + ssl->transform_in->ctx_inflate.avail_out = SSL_MAX_CONTENT_LEN; + + ret = inflate( &ssl->transform_in->ctx_inflate, Z_SYNC_FLUSH ); + if( ret != Z_OK ) + { + SSL_DEBUG_MSG( 1, ( "failed to perform decompression (%d)", ret ) ); + return( POLARSSL_ERR_SSL_COMPRESSION_FAILED ); + } + + ssl->in_msglen = SSL_MAX_CONTENT_LEN - ssl->transform_in->ctx_inflate.avail_out; + + free( msg_pre ); + + SSL_DEBUG_MSG( 3, ( "after decompression: msglen = %d, ", + ssl->in_msglen ) ); + + SSL_DEBUG_BUF( 4, "after decompression: input payload", + ssl->in_msg, ssl->in_msglen ); + + SSL_DEBUG_MSG( 2, ( "<= decompress buf" ) ); + + return( 0 ); +} +#endif /* POLARSSL_ZLIB_SUPPORT */ + +/* + * Fill the input message buffer + */ +int ssl_fetch_input( ssl_context *ssl, size_t nb_want ) +{ + int ret; + size_t len; + + SSL_DEBUG_MSG( 2, ( "=> fetch input" ) ); + + while( ssl->in_left < nb_want ) + { + len = nb_want - ssl->in_left; + ret = ssl->f_recv( ssl->p_recv, ssl->in_hdr + ssl->in_left, len ); + + SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", + ssl->in_left, nb_want ) ); + SSL_DEBUG_RET( 2, "ssl->f_recv", ret ); + + if( ret == 0 ) + return( POLARSSL_ERR_SSL_CONN_EOF ); + + if( ret < 0 ) + return( ret ); + + ssl->in_left += ret; + } + + SSL_DEBUG_MSG( 2, ( "<= fetch input" ) ); + + return( 0 ); +} + +/* + * Flush any data not yet written + */ +int ssl_flush_output( ssl_context *ssl ) +{ + int ret; + unsigned char *buf; + + SSL_DEBUG_MSG( 2, ( "=> flush output" ) ); + + while( ssl->out_left > 0 ) + { + SSL_DEBUG_MSG( 2, ( "message length: %d, out_left: %d", + 5 + ssl->out_msglen, ssl->out_left ) ); + + if( ssl->out_msglen < ssl->out_left ) + { + size_t header_left = ssl->out_left - ssl->out_msglen; + + buf = ssl->out_hdr + 5 - header_left; + ret = ssl->f_send( ssl->p_send, buf, header_left ); + + SSL_DEBUG_RET( 2, "ssl->f_send (header)", ret ); + + if( ret <= 0 ) + return( ret ); + + ssl->out_left -= ret; + } + + buf = ssl->out_msg + ssl->out_msglen - ssl->out_left; + ret = ssl->f_send( ssl->p_send, buf, ssl->out_left ); + + SSL_DEBUG_RET( 2, "ssl->f_send", ret ); + + if( ret <= 0 ) + return( ret ); + + ssl->out_left -= ret; + } + + SSL_DEBUG_MSG( 2, ( "<= flush output" ) ); + + return( 0 ); +} + +/* + * Record layer functions + */ +int ssl_write_record( ssl_context *ssl ) +{ + int ret, done = 0; + size_t len = ssl->out_msglen; + + SSL_DEBUG_MSG( 2, ( "=> write record" ) ); + + if( ssl->out_msgtype == SSL_MSG_HANDSHAKE ) + { + ssl->out_msg[1] = (unsigned char)( ( len - 4 ) >> 16 ); + ssl->out_msg[2] = (unsigned char)( ( len - 4 ) >> 8 ); + ssl->out_msg[3] = (unsigned char)( ( len - 4 ) ); + + ssl->handshake->update_checksum( ssl, ssl->out_msg, len ); + } + +#if defined(POLARSSL_ZLIB_SUPPORT) + if( ssl->transform_out != NULL && + ssl->session_out->compression == SSL_COMPRESS_DEFLATE ) + { + if( ( ret = ssl_compress_buf( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_compress_buf", ret ); + return( ret ); + } + + len = ssl->out_msglen; + } +#endif /*POLARSSL_ZLIB_SUPPORT */ + +#if defined(POLARSSL_SSL_HW_RECORD_ACCEL) + if( ssl_hw_record_write != NULL) + { + SSL_DEBUG_MSG( 2, ( "going for ssl_hw_record_write()" ) ); + + ret = ssl_hw_record_write( ssl ); + if( ret != 0 && ret != POLARSSL_ERR_SSL_HW_ACCEL_FALLTHROUGH ) + { + SSL_DEBUG_RET( 1, "ssl_hw_record_write", ret ); + return POLARSSL_ERR_SSL_HW_ACCEL_FAILED; + } + done = 1; + } +#endif + if( !done ) + { + ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype; + ssl->out_hdr[1] = (unsigned char) ssl->major_ver; + ssl->out_hdr[2] = (unsigned char) ssl->minor_ver; + ssl->out_hdr[3] = (unsigned char)( len >> 8 ); + ssl->out_hdr[4] = (unsigned char)( len ); + + if( ssl->transform_out != NULL ) + { + if( ( ret = ssl_encrypt_buf( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_encrypt_buf", ret ); + return( ret ); + } + + len = ssl->out_msglen; + ssl->out_hdr[3] = (unsigned char)( len >> 8 ); + ssl->out_hdr[4] = (unsigned char)( len ); + } + + ssl->out_left = 5 + ssl->out_msglen; + + SSL_DEBUG_MSG( 3, ( "output record: msgtype = %d, " + "version = [%d:%d], msglen = %d", + ssl->out_hdr[0], ssl->out_hdr[1], ssl->out_hdr[2], + ( ssl->out_hdr[3] << 8 ) | ssl->out_hdr[4] ) ); + + SSL_DEBUG_BUF( 4, "output record header sent to network", + ssl->out_hdr, 5 ); + SSL_DEBUG_BUF( 4, "output record sent to network", + ssl->out_hdr + 32, ssl->out_msglen ); + } + + if( ( ret = ssl_flush_output( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_flush_output", ret ); + return( ret ); + } + + SSL_DEBUG_MSG( 2, ( "<= write record" ) ); + + return( 0 ); +} + +int ssl_read_record( ssl_context *ssl ) +{ + int ret, done = 0; + + SSL_DEBUG_MSG( 2, ( "=> read record" ) ); + + if( ssl->in_hslen != 0 && + ssl->in_hslen < ssl->in_msglen ) + { + /* + * Get next Handshake message in the current record + */ + ssl->in_msglen -= ssl->in_hslen; + + memmove( ssl->in_msg, ssl->in_msg + ssl->in_hslen, + ssl->in_msglen ); + + ssl->in_hslen = 4; + ssl->in_hslen += ( ssl->in_msg[2] << 8 ) | ssl->in_msg[3]; + + SSL_DEBUG_MSG( 3, ( "handshake message: msglen =" + " %d, type = %d, hslen = %d", + ssl->in_msglen, ssl->in_msg[0], ssl->in_hslen ) ); + + if( ssl->in_msglen < 4 || ssl->in_msg[1] != 0 ) + { + SSL_DEBUG_MSG( 1, ( "bad handshake length" ) ); + return( POLARSSL_ERR_SSL_INVALID_RECORD ); + } + + if( ssl->in_msglen < ssl->in_hslen ) + { + SSL_DEBUG_MSG( 1, ( "bad handshake length" ) ); + return( POLARSSL_ERR_SSL_INVALID_RECORD ); + } + + ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen ); + + return( 0 ); + } + + ssl->in_hslen = 0; + + /* + * Read the record header and validate it + */ + if( ( ret = ssl_fetch_input( ssl, 5 ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_fetch_input", ret ); + return( ret ); + } + + ssl->in_msgtype = ssl->in_hdr[0]; + ssl->in_msglen = ( ssl->in_hdr[3] << 8 ) | ssl->in_hdr[4]; + + SSL_DEBUG_MSG( 3, ( "input record: msgtype = %d, " + "version = [%d:%d], msglen = %d", + ssl->in_hdr[0], ssl->in_hdr[1], ssl->in_hdr[2], + ( ssl->in_hdr[3] << 8 ) | ssl->in_hdr[4] ) ); + + if( ssl->in_hdr[1] != ssl->major_ver ) + { + SSL_DEBUG_MSG( 1, ( "major version mismatch" ) ); + return( POLARSSL_ERR_SSL_INVALID_RECORD ); + } + + if( ssl->in_hdr[2] > ssl->max_minor_ver ) + { + SSL_DEBUG_MSG( 1, ( "minor version mismatch" ) ); + return( POLARSSL_ERR_SSL_INVALID_RECORD ); + } + + /* + * Make sure the message length is acceptable + */ + if( ssl->transform_in == NULL ) + { + if( ssl->in_msglen < 1 || + ssl->in_msglen > SSL_MAX_CONTENT_LEN ) + { + SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( POLARSSL_ERR_SSL_INVALID_RECORD ); + } + } + else + { + if( ssl->in_msglen < ssl->transform_in->minlen ) + { + SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( POLARSSL_ERR_SSL_INVALID_RECORD ); + } + + if( ssl->minor_ver == SSL_MINOR_VERSION_0 && + ssl->in_msglen > ssl->transform_in->minlen + SSL_MAX_CONTENT_LEN ) + { + SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( POLARSSL_ERR_SSL_INVALID_RECORD ); + } + + /* + * TLS encrypted messages can have up to 256 bytes of padding + */ + if( ssl->minor_ver >= SSL_MINOR_VERSION_1 && + ssl->in_msglen > ssl->transform_in->minlen + SSL_MAX_CONTENT_LEN + 256 ) + { + SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( POLARSSL_ERR_SSL_INVALID_RECORD ); + } + } + + /* + * Read and optionally decrypt the message contents + */ + if( ( ret = ssl_fetch_input( ssl, 5 + ssl->in_msglen ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_fetch_input", ret ); + return( ret ); + } + + SSL_DEBUG_BUF( 4, "input record from network", + ssl->in_hdr, 5 + ssl->in_msglen ); + +#if defined(POLARSSL_SSL_HW_RECORD_ACCEL) + if( ssl_hw_record_read != NULL) + { + SSL_DEBUG_MSG( 2, ( "going for ssl_hw_record_read()" ) ); + + ret = ssl_hw_record_read( ssl ); + if( ret != 0 && ret != POLARSSL_ERR_SSL_HW_ACCEL_FALLTHROUGH ) + { + SSL_DEBUG_RET( 1, "ssl_hw_record_read", ret ); + return POLARSSL_ERR_SSL_HW_ACCEL_FAILED; + } + done = 1; + } +#endif + if( !done && ssl->transform_in != NULL ) + { + if( ( ret = ssl_decrypt_buf( ssl ) ) != 0 ) + { +#if defined(POLARSSL_SSL_ALERT_MESSAGES) + if( ret == POLARSSL_ERR_SSL_INVALID_MAC ) + { + ssl_send_alert_message( ssl, + SSL_ALERT_LEVEL_FATAL, + SSL_ALERT_MSG_BAD_RECORD_MAC ); + } +#endif + SSL_DEBUG_RET( 1, "ssl_decrypt_buf", ret ); + return( ret ); + } + + SSL_DEBUG_BUF( 4, "input payload after decrypt", + ssl->in_msg, ssl->in_msglen ); + + if( ssl->in_msglen > SSL_MAX_CONTENT_LEN ) + { + SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( POLARSSL_ERR_SSL_INVALID_RECORD ); + } + } + +#if defined(POLARSSL_ZLIB_SUPPORT) + if( ssl->transform_in != NULL && + ssl->session_in->compression == SSL_COMPRESS_DEFLATE ) + { + if( ( ret = ssl_decompress_buf( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_decompress_buf", ret ); + return( ret ); + } + + ssl->in_hdr[3] = (unsigned char)( ssl->in_msglen >> 8 ); + ssl->in_hdr[4] = (unsigned char)( ssl->in_msglen ); + } +#endif /* POLARSSL_ZLIB_SUPPORT */ + + if( ssl->in_msgtype != SSL_MSG_HANDSHAKE && + ssl->in_msgtype != SSL_MSG_ALERT && + ssl->in_msgtype != SSL_MSG_CHANGE_CIPHER_SPEC && + ssl->in_msgtype != SSL_MSG_APPLICATION_DATA ) + { + SSL_DEBUG_MSG( 1, ( "unknown record type" ) ); + + if( ( ret = ssl_send_alert_message( ssl, + SSL_ALERT_LEVEL_FATAL, + SSL_ALERT_MSG_UNEXPECTED_MESSAGE ) ) != 0 ) + { + return( ret ); + } + + return( POLARSSL_ERR_SSL_INVALID_RECORD ); + } + + if( ssl->in_msgtype == SSL_MSG_HANDSHAKE ) + { + ssl->in_hslen = 4; + ssl->in_hslen += ( ssl->in_msg[2] << 8 ) | ssl->in_msg[3]; + + SSL_DEBUG_MSG( 3, ( "handshake message: msglen =" + " %d, type = %d, hslen = %d", + ssl->in_msglen, ssl->in_msg[0], ssl->in_hslen ) ); + + /* + * Additional checks to validate the handshake header + */ + if( ssl->in_msglen < 4 || ssl->in_msg[1] != 0 ) + { + SSL_DEBUG_MSG( 1, ( "bad handshake length" ) ); + return( POLARSSL_ERR_SSL_INVALID_RECORD ); + } + + if( ssl->in_msglen < ssl->in_hslen ) + { + SSL_DEBUG_MSG( 1, ( "bad handshake length" ) ); + return( POLARSSL_ERR_SSL_INVALID_RECORD ); + } + + if( ssl->state != SSL_HANDSHAKE_OVER ) + ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen ); + } + + if( ssl->in_msgtype == SSL_MSG_ALERT ) + { + SSL_DEBUG_MSG( 2, ( "got an alert message, type: [%d:%d]", + ssl->in_msg[0], ssl->in_msg[1] ) ); + + /* + * Ignore non-fatal alerts, except close_notify + */ + if( ssl->in_msg[0] == SSL_ALERT_LEVEL_FATAL ) + { + SSL_DEBUG_MSG( 1, ( "is a fatal alert message (msg %d)", + ssl->in_msg[1] ) ); + /** + * Subtract from error code as ssl->in_msg[1] is 7-bit positive + * error identifier. + */ + return( POLARSSL_ERR_SSL_FATAL_ALERT_MESSAGE ); + } + + if( ssl->in_msg[0] == SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == SSL_ALERT_MSG_CLOSE_NOTIFY ) + { + SSL_DEBUG_MSG( 2, ( "is a close notify message" ) ); + return( POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY ); + } + } + + ssl->in_left = 0; + + SSL_DEBUG_MSG( 2, ( "<= read record" ) ); + + return( 0 ); +} + +int ssl_send_fatal_handshake_failure( ssl_context *ssl ) +{ + int ret; + + if( ( ret = ssl_send_alert_message( ssl, + SSL_ALERT_LEVEL_FATAL, + SSL_ALERT_MSG_HANDSHAKE_FAILURE ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +int ssl_send_alert_message( ssl_context *ssl, + unsigned char level, + unsigned char message ) +{ + int ret; + + SSL_DEBUG_MSG( 2, ( "=> send alert message" ) ); + + ssl->out_msgtype = SSL_MSG_ALERT; + ssl->out_msglen = 2; + ssl->out_msg[0] = level; + ssl->out_msg[1] = message; + + if( ( ret = ssl_write_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + + SSL_DEBUG_MSG( 2, ( "<= send alert message" ) ); + + return( 0 ); +} + +/* + * Handshake functions + */ +int ssl_write_certificate( ssl_context *ssl ) +{ + int ret; + size_t i, n; + const x509_cert *crt; + + SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); + + if( ssl->endpoint == SSL_IS_CLIENT ) + { + if( ssl->client_auth == 0 ) + { + SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + ssl->state++; + return( 0 ); + } + + /* + * If using SSLv3 and got no cert, send an Alert message + * (otherwise an empty Certificate message will be sent). + */ + if( ssl->own_cert == NULL && + ssl->minor_ver == SSL_MINOR_VERSION_0 ) + { + ssl->out_msglen = 2; + ssl->out_msgtype = SSL_MSG_ALERT; + ssl->out_msg[0] = SSL_ALERT_LEVEL_WARNING; + ssl->out_msg[1] = SSL_ALERT_MSG_NO_CERT; + + SSL_DEBUG_MSG( 2, ( "got no certificate to send" ) ); + goto write_msg; + } + } + else /* SSL_IS_SERVER */ + { + if( ssl->own_cert == NULL ) + { + SSL_DEBUG_MSG( 1, ( "got no certificate to send" ) ); + return( POLARSSL_ERR_SSL_CERTIFICATE_REQUIRED ); + } + } + + SSL_DEBUG_CRT( 3, "own certificate", ssl->own_cert ); + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 6 length of all certs + * 7 . 9 length of cert. 1 + * 10 . n-1 peer certificate + * n . n+2 length of cert. 2 + * n+3 . ... upper level cert, etc. + */ + i = 7; + crt = ssl->own_cert; + + while( crt != NULL ) + { + n = crt->raw.len; + if( i + 3 + n > SSL_MAX_CONTENT_LEN ) + { + SSL_DEBUG_MSG( 1, ( "certificate too large, %d > %d", + i + 3 + n, SSL_MAX_CONTENT_LEN ) ); + return( POLARSSL_ERR_SSL_CERTIFICATE_TOO_LARGE ); + } + + ssl->out_msg[i ] = (unsigned char)( n >> 16 ); + ssl->out_msg[i + 1] = (unsigned char)( n >> 8 ); + ssl->out_msg[i + 2] = (unsigned char)( n ); + + i += 3; memcpy( ssl->out_msg + i, crt->raw.p, n ); + i += n; crt = crt->next; + } + + ssl->out_msg[4] = (unsigned char)( ( i - 7 ) >> 16 ); + ssl->out_msg[5] = (unsigned char)( ( i - 7 ) >> 8 ); + ssl->out_msg[6] = (unsigned char)( ( i - 7 ) ); + + ssl->out_msglen = i; + ssl->out_msgtype = SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = SSL_HS_CERTIFICATE; + +write_msg: + + ssl->state++; + + if( ( ret = ssl_write_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + + SSL_DEBUG_MSG( 2, ( "<= write certificate" ) ); + + return( 0 ); +} + +int ssl_parse_certificate( ssl_context *ssl ) +{ + int ret; + size_t i, n; + + SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + if( ssl->endpoint == SSL_IS_SERVER && + ssl->authmode == SSL_VERIFY_NONE ) + { + ssl->verify_result = BADCERT_SKIP_VERIFY; + SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } + + if( ( ret = ssl_read_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_read_record", ret ); + return( ret ); + } + + ssl->state++; + + /* + * Check if the client sent an empty certificate + */ + if( ssl->endpoint == SSL_IS_SERVER && + ssl->minor_ver == SSL_MINOR_VERSION_0 ) + { + if( ssl->in_msglen == 2 && + ssl->in_msgtype == SSL_MSG_ALERT && + ssl->in_msg[0] == SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == SSL_ALERT_MSG_NO_CERT ) + { + SSL_DEBUG_MSG( 1, ( "SSLv3 client has no certificate" ) ); + + ssl->verify_result = BADCERT_MISSING; + if( ssl->authmode == SSL_VERIFY_OPTIONAL ) + return( 0 ); + else + return( POLARSSL_ERR_SSL_NO_CLIENT_CERTIFICATE ); + } + } + + if( ssl->endpoint == SSL_IS_SERVER && + ssl->minor_ver != SSL_MINOR_VERSION_0 ) + { + if( ssl->in_hslen == 7 && + ssl->in_msgtype == SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == SSL_HS_CERTIFICATE && + memcmp( ssl->in_msg + 4, "\0\0\0", 3 ) == 0 ) + { + SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) ); + + ssl->verify_result = BADCERT_MISSING; + if( ssl->authmode == SSL_VERIFY_REQUIRED ) + return( POLARSSL_ERR_SSL_NO_CLIENT_CERTIFICATE ); + else + return( 0 ); + } + } + + if( ssl->in_msgtype != SSL_MSG_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->in_msg[0] != SSL_HS_CERTIFICATE || ssl->in_hslen < 10 ) + { + SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + /* + * Same message structure as in ssl_write_certificate() + */ + n = ( ssl->in_msg[5] << 8 ) | ssl->in_msg[6]; + + if( ssl->in_msg[4] != 0 || ssl->in_hslen != 7 + n ) + { + SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + if( ( ssl->session_negotiate->peer_cert = (x509_cert *) malloc( + sizeof( x509_cert ) ) ) == NULL ) + { + SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", + sizeof( x509_cert ) ) ); + return( POLARSSL_ERR_SSL_MALLOC_FAILED ); + } + + memset( ssl->session_negotiate->peer_cert, 0, sizeof( x509_cert ) ); + + i = 7; + + while( i < ssl->in_hslen ) + { + if( ssl->in_msg[i] != 0 ) + { + SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + n = ( (unsigned int) ssl->in_msg[i + 1] << 8 ) + | (unsigned int) ssl->in_msg[i + 2]; + i += 3; + + if( n < 128 || i + n > ssl->in_hslen ) + { + SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + ret = x509parse_crt_der( ssl->session_negotiate->peer_cert, + ssl->in_msg + i, n ); + if( ret != 0 ) + { + SSL_DEBUG_RET( 1, " x509parse_crt", ret ); + return( ret ); + } + + i += n; + } + + SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert ); + + if( ssl->authmode != SSL_VERIFY_NONE ) + { + if( ssl->ca_chain == NULL ) + { + SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); + return( POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED ); + } + + ret = x509parse_verify( ssl->session_negotiate->peer_cert, + ssl->ca_chain, ssl->ca_crl, + ssl->peer_cn, &ssl->verify_result, + ssl->f_vrfy, ssl->p_vrfy ); + + if( ret != 0 ) + SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); + + if( ssl->authmode != SSL_VERIFY_REQUIRED ) + ret = 0; + } + + SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) ); + + return( ret ); +} + +int ssl_write_change_cipher_spec( ssl_context *ssl ) +{ + int ret; + + SSL_DEBUG_MSG( 2, ( "=> write change cipher spec" ) ); + + ssl->out_msgtype = SSL_MSG_CHANGE_CIPHER_SPEC; + ssl->out_msglen = 1; + ssl->out_msg[0] = 1; + + ssl->state++; + + if( ( ret = ssl_write_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + + SSL_DEBUG_MSG( 2, ( "<= write change cipher spec" ) ); + + return( 0 ); +} + +int ssl_parse_change_cipher_spec( ssl_context *ssl ) +{ + int ret; + + SSL_DEBUG_MSG( 2, ( "=> parse change cipher spec" ) ); + + if( ( ret = ssl_read_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != SSL_MSG_CHANGE_CIPHER_SPEC ) + { + SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) ); + return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->in_msglen != 1 || ssl->in_msg[0] != 1 ) + { + SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC ); + } + + ssl->state++; + + SSL_DEBUG_MSG( 2, ( "<= parse change cipher spec" ) ); + + return( 0 ); +} + +void ssl_optimize_checksum( ssl_context *ssl, int ciphersuite ) +{ +#if !defined(POLARSSL_SHA4_C) + ((void) ciphersuite); +#endif + + if( ssl->minor_ver < SSL_MINOR_VERSION_3 ) + ssl->handshake->update_checksum = ssl_update_checksum_md5sha1; +#if defined(POLARSSL_SHA4_C) + else if ( ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 || + ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ) + { + ssl->handshake->update_checksum = ssl_update_checksum_sha384; + } +#endif + else + ssl->handshake->update_checksum = ssl_update_checksum_sha256; +} + +static void ssl_update_checksum_start( ssl_context *ssl, unsigned char *buf, + size_t len ) +{ + md5_update( &ssl->handshake->fin_md5 , buf, len ); + sha1_update( &ssl->handshake->fin_sha1, buf, len ); + sha2_update( &ssl->handshake->fin_sha2, buf, len ); +#if defined(POLARSSL_SHA4_C) + sha4_update( &ssl->handshake->fin_sha4, buf, len ); +#endif +} + +static void ssl_update_checksum_md5sha1( ssl_context *ssl, unsigned char *buf, + size_t len ) +{ + md5_update( &ssl->handshake->fin_md5 , buf, len ); + sha1_update( &ssl->handshake->fin_sha1, buf, len ); +} + +static void ssl_update_checksum_sha256( ssl_context *ssl, unsigned char *buf, + size_t len ) +{ + sha2_update( &ssl->handshake->fin_sha2, buf, len ); +} + +#if defined(POLARSSL_SHA4_C) +static void ssl_update_checksum_sha384( ssl_context *ssl, unsigned char *buf, + size_t len ) +{ + sha4_update( &ssl->handshake->fin_sha4, buf, len ); +} +#endif + +static void ssl_calc_finished_ssl( + ssl_context *ssl, unsigned char *buf, int from ) +{ + const char *sender; + md5_context md5; + sha1_context sha1; + + unsigned char padbuf[48]; + unsigned char md5sum[16]; + unsigned char sha1sum[20]; + + ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + SSL_DEBUG_MSG( 2, ( "=> calc finished ssl" ) ); + + memcpy( &md5 , &ssl->handshake->fin_md5 , sizeof(md5_context) ); + memcpy( &sha1, &ssl->handshake->fin_sha1, sizeof(sha1_context) ); + + /* + * SSLv3: + * hash = + * MD5( master + pad2 + + * MD5( handshake + sender + master + pad1 ) ) + * + SHA1( master + pad2 + + * SHA1( handshake + sender + master + pad1 ) ) + */ + +#if !defined(POLARSSL_MD5_ALT) + SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *) + md5.state, sizeof( md5.state ) ); +#endif + +#if !defined(POLARSSL_SHA1_ALT) + SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *) + sha1.state, sizeof( sha1.state ) ); +#endif + + sender = ( from == SSL_IS_CLIENT ) ? "CLNT" + : "SRVR"; + + memset( padbuf, 0x36, 48 ); + + md5_update( &md5, (const unsigned char *) sender, 4 ); + md5_update( &md5, session->master, 48 ); + md5_update( &md5, padbuf, 48 ); + md5_finish( &md5, md5sum ); + + sha1_update( &sha1, (const unsigned char *) sender, 4 ); + sha1_update( &sha1, session->master, 48 ); + sha1_update( &sha1, padbuf, 40 ); + sha1_finish( &sha1, sha1sum ); + + memset( padbuf, 0x5C, 48 ); + + md5_starts( &md5 ); + md5_update( &md5, session->master, 48 ); + md5_update( &md5, padbuf, 48 ); + md5_update( &md5, md5sum, 16 ); + md5_finish( &md5, buf ); + + sha1_starts( &sha1 ); + sha1_update( &sha1, session->master, 48 ); + sha1_update( &sha1, padbuf , 40 ); + sha1_update( &sha1, sha1sum, 20 ); + sha1_finish( &sha1, buf + 16 ); + + SSL_DEBUG_BUF( 3, "calc finished result", buf, 36 ); + + memset( &md5, 0, sizeof( md5_context ) ); + memset( &sha1, 0, sizeof( sha1_context ) ); + + memset( padbuf, 0, sizeof( padbuf ) ); + memset( md5sum, 0, sizeof( md5sum ) ); + memset( sha1sum, 0, sizeof( sha1sum ) ); + + SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} + +static void ssl_calc_finished_tls( + ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + const char *sender; + md5_context md5; + sha1_context sha1; + unsigned char padbuf[36]; + + ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + SSL_DEBUG_MSG( 2, ( "=> calc finished tls" ) ); + + memcpy( &md5 , &ssl->handshake->fin_md5 , sizeof(md5_context) ); + memcpy( &sha1, &ssl->handshake->fin_sha1, sizeof(sha1_context) ); + + /* + * TLSv1: + * hash = PRF( master, finished_label, + * MD5( handshake ) + SHA1( handshake ) )[0..11] + */ + +#if !defined(POLARSSL_MD5_ALT) + SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *) + md5.state, sizeof( md5.state ) ); +#endif + +#if !defined(POLARSSL_SHA1_ALT) + SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *) + sha1.state, sizeof( sha1.state ) ); +#endif + + sender = ( from == SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + + md5_finish( &md5, padbuf ); + sha1_finish( &sha1, padbuf + 16 ); + + ssl->handshake->tls_prf( session->master, 48, (char *) sender, + padbuf, 36, buf, len ); + + SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + memset( &md5, 0, sizeof( md5_context ) ); + memset( &sha1, 0, sizeof( sha1_context ) ); + + memset( padbuf, 0, sizeof( padbuf ) ); + + SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} + +static void ssl_calc_finished_tls_sha256( + ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + const char *sender; + sha2_context sha2; + unsigned char padbuf[32]; + + ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + SSL_DEBUG_MSG( 2, ( "=> calc finished tls sha256" ) ); + + memcpy( &sha2, &ssl->handshake->fin_sha2, sizeof(sha2_context) ); + + /* + * TLSv1.2: + * hash = PRF( master, finished_label, + * Hash( handshake ) )[0.11] + */ + +#if !defined(POLARSSL_SHA2_ALT) + SSL_DEBUG_BUF( 4, "finished sha2 state", (unsigned char *) + sha2.state, sizeof( sha2.state ) ); +#endif + + sender = ( from == SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + + sha2_finish( &sha2, padbuf ); + + ssl->handshake->tls_prf( session->master, 48, (char *) sender, + padbuf, 32, buf, len ); + + SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + memset( &sha2, 0, sizeof( sha2_context ) ); + + memset( padbuf, 0, sizeof( padbuf ) ); + + SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} + +#if defined(POLARSSL_SHA4_C) +static void ssl_calc_finished_tls_sha384( + ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + const char *sender; + sha4_context sha4; + unsigned char padbuf[48]; + + ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + SSL_DEBUG_MSG( 2, ( "=> calc finished tls sha384" ) ); + + memcpy( &sha4, &ssl->handshake->fin_sha4, sizeof(sha4_context) ); + + /* + * TLSv1.2: + * hash = PRF( master, finished_label, + * Hash( handshake ) )[0.11] + */ + +#if !defined(POLARSSL_SHA4_ALT) + SSL_DEBUG_BUF( 4, "finished sha4 state", (unsigned char *) + sha4.state, sizeof( sha4.state ) ); +#endif + + sender = ( from == SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + + sha4_finish( &sha4, padbuf ); + + ssl->handshake->tls_prf( session->master, 48, (char *) sender, + padbuf, 48, buf, len ); + + SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + memset( &sha4, 0, sizeof( sha4_context ) ); + + memset( padbuf, 0, sizeof( padbuf ) ); + + SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif + +void ssl_handshake_wrapup( ssl_context *ssl ) +{ + SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) ); + + /* + * Free our handshake params + */ + ssl_handshake_free( ssl->handshake ); + free( ssl->handshake ); + ssl->handshake = NULL; + + /* + * Switch in our now active transform context + */ + if( ssl->transform ) + { + ssl_transform_free( ssl->transform ); + free( ssl->transform ); + } + ssl->transform = ssl->transform_negotiate; + ssl->transform_negotiate = NULL; + + if( ssl->session ) + { + ssl_session_free( ssl->session ); + free( ssl->session ); + } + ssl->session = ssl->session_negotiate; + ssl->session_negotiate = NULL; + + /* + * Add cache entry + */ + if( ssl->f_set_cache != NULL ) + if( ssl->f_set_cache( ssl->p_set_cache, ssl->session ) != 0 ) + SSL_DEBUG_MSG( 1, ( "cache did not store session" ) ); + + ssl->state++; + + SSL_DEBUG_MSG( 3, ( "<= handshake wrapup" ) ); +} + +int ssl_write_finished( ssl_context *ssl ) +{ + int ret, hash_len; + + SSL_DEBUG_MSG( 2, ( "=> write finished" ) ); + + ssl->handshake->calc_finished( ssl, ssl->out_msg + 4, ssl->endpoint ); + + // TODO TLS/1.2 Hash length is determined by cipher suite (Page 63) + hash_len = ( ssl->minor_ver == SSL_MINOR_VERSION_0 ) ? 36 : 12; + + ssl->verify_data_len = hash_len; + memcpy( ssl->own_verify_data, ssl->out_msg + 4, hash_len ); + + ssl->out_msglen = 4 + hash_len; + ssl->out_msgtype = SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = SSL_HS_FINISHED; + + /* + * In case of session resuming, invert the client and server + * ChangeCipherSpec messages order. + */ + if( ssl->handshake->resume != 0 ) + { + if( ssl->endpoint == SSL_IS_CLIENT ) + ssl->state = SSL_HANDSHAKE_WRAPUP; + else + ssl->state = SSL_CLIENT_CHANGE_CIPHER_SPEC; + } + else + ssl->state++; + + /* + * Switch to our negotiated transform and session parameters for outbound data. + */ + SSL_DEBUG_MSG( 3, ( "switching to new transform spec for outbound data" ) ); + ssl->transform_out = ssl->transform_negotiate; + ssl->session_out = ssl->session_negotiate; + memset( ssl->out_ctr, 0, 8 ); + + if( ( ret = ssl_write_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + + SSL_DEBUG_MSG( 2, ( "<= write finished" ) ); + + return( 0 ); +} + +int ssl_parse_finished( ssl_context *ssl ) +{ + int ret; + unsigned int hash_len; + unsigned char buf[36]; + + SSL_DEBUG_MSG( 2, ( "=> parse finished" ) ); + + ssl->handshake->calc_finished( ssl, buf, ssl->endpoint ^ 1 ); + + /* + * Switch to our negotiated transform and session parameters for inbound data. + */ + SSL_DEBUG_MSG( 3, ( "switching to new transform spec for inbound data" ) ); + ssl->transform_in = ssl->transform_negotiate; + ssl->session_in = ssl->session_negotiate; + memset( ssl->in_ctr, 0, 8 ); + + if( ( ret = ssl_read_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != SSL_MSG_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + // TODO TLS/1.2 Hash length is determined by cipher suite (Page 63) + hash_len = ( ssl->minor_ver == SSL_MINOR_VERSION_0 ) ? 36 : 12; + + if( ssl->in_msg[0] != SSL_HS_FINISHED || + ssl->in_hslen != 4 + hash_len ) + { + SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_FINISHED ); + } + + if( memcmp( ssl->in_msg + 4, buf, hash_len ) != 0 ) + { + SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_FINISHED ); + } + + ssl->verify_data_len = hash_len; + memcpy( ssl->peer_verify_data, buf, hash_len ); + + if( ssl->handshake->resume != 0 ) + { + if( ssl->endpoint == SSL_IS_CLIENT ) + ssl->state = SSL_CLIENT_CHANGE_CIPHER_SPEC; + + if( ssl->endpoint == SSL_IS_SERVER ) + ssl->state = SSL_HANDSHAKE_WRAPUP; + } + else + ssl->state++; + + SSL_DEBUG_MSG( 2, ( "<= parse finished" ) ); + + return( 0 ); +} + +int ssl_handshake_init( ssl_context *ssl ) +{ + if( ssl->transform_negotiate ) + ssl_transform_free( ssl->transform_negotiate ); + else + ssl->transform_negotiate = malloc( sizeof(ssl_transform) ); + + if( ssl->session_negotiate ) + ssl_session_free( ssl->session_negotiate ); + else + ssl->session_negotiate = malloc( sizeof(ssl_session) ); + + if( ssl->handshake ) + ssl_handshake_free( ssl->handshake ); + else + ssl->handshake = malloc( sizeof(ssl_handshake_params) ); + + if( ssl->handshake == NULL || + ssl->transform_negotiate == NULL || + ssl->session_negotiate == NULL ) + { + SSL_DEBUG_MSG( 1, ( "malloc() of ssl sub-contexts failed" ) ); + return( POLARSSL_ERR_SSL_MALLOC_FAILED ); + } + + memset( ssl->handshake, 0, sizeof(ssl_handshake_params) ); + memset( ssl->transform_negotiate, 0, sizeof(ssl_transform) ); + memset( ssl->session_negotiate, 0, sizeof(ssl_session) ); + + md5_starts( &ssl->handshake->fin_md5 ); + sha1_starts( &ssl->handshake->fin_sha1 ); + sha2_starts( &ssl->handshake->fin_sha2, 0 ); +#if defined(POLARSSL_SHA4_C) + sha4_starts( &ssl->handshake->fin_sha4, 1 ); +#endif + + ssl->handshake->update_checksum = ssl_update_checksum_start; + ssl->handshake->sig_alg = SSL_HASH_SHA1; + + return( 0 ); +} + +/* + * Initialize an SSL context + */ +int ssl_init( ssl_context *ssl ) +{ + int ret; + int len = SSL_BUFFER_LEN; + + memset( ssl, 0, sizeof( ssl_context ) ); + + /* + * Sane defaults + */ + ssl->rsa_decrypt = ssl_rsa_decrypt; + ssl->rsa_sign = ssl_rsa_sign; + ssl->rsa_key_len = ssl_rsa_key_len; + + ssl->min_major_ver = SSL_MAJOR_VERSION_3; + ssl->min_minor_ver = SSL_MINOR_VERSION_0; + + ssl->ciphersuites = malloc( sizeof(int *) * 4 ); + ssl_set_ciphersuites( ssl, ssl_default_ciphersuites ); + +#if defined(POLARSSL_DHM_C) + if( ( ret = mpi_read_string( &ssl->dhm_P, 16, + POLARSSL_DHM_RFC5114_MODP_1024_P) ) != 0 || + ( ret = mpi_read_string( &ssl->dhm_G, 16, + POLARSSL_DHM_RFC5114_MODP_1024_G) ) != 0 ) + { + SSL_DEBUG_RET( 1, "mpi_read_string", ret ); + return( ret ); + } +#endif + + /* + * Prepare base structures + */ + ssl->in_ctr = (unsigned char *) malloc( len ); + ssl->in_hdr = ssl->in_ctr + 8; + ssl->in_msg = ssl->in_ctr + 13; + + if( ssl->in_ctr == NULL ) + { + SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len ) ); + return( POLARSSL_ERR_SSL_MALLOC_FAILED ); + } + + ssl->out_ctr = (unsigned char *) malloc( len ); + ssl->out_hdr = ssl->out_ctr + 8; + ssl->out_msg = ssl->out_ctr + 40; + + if( ssl->out_ctr == NULL ) + { + SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len ) ); + free( ssl-> in_ctr ); + return( POLARSSL_ERR_SSL_MALLOC_FAILED ); + } + + memset( ssl-> in_ctr, 0, SSL_BUFFER_LEN ); + memset( ssl->out_ctr, 0, SSL_BUFFER_LEN ); + + ssl->hostname = NULL; + ssl->hostname_len = 0; + + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Reset an initialized and used SSL context for re-use while retaining + * all application-set variables, function pointers and data. + */ +int ssl_session_reset( ssl_context *ssl ) +{ + int ret; + + ssl->state = SSL_HELLO_REQUEST; + ssl->renegotiation = SSL_INITIAL_HANDSHAKE; + ssl->secure_renegotiation = SSL_LEGACY_RENEGOTIATION; + + ssl->verify_data_len = 0; + memset( ssl->own_verify_data, 0, 36 ); + memset( ssl->peer_verify_data, 0, 36 ); + + ssl->in_offt = NULL; + + ssl->in_msgtype = 0; + ssl->in_msglen = 0; + ssl->in_left = 0; + + ssl->in_hslen = 0; + ssl->nb_zero = 0; + + ssl->out_msgtype = 0; + ssl->out_msglen = 0; + ssl->out_left = 0; + + ssl->transform_in = NULL; + ssl->transform_out = NULL; + + memset( ssl->out_ctr, 0, SSL_BUFFER_LEN ); + memset( ssl->in_ctr, 0, SSL_BUFFER_LEN ); + +#if defined(POLARSSL_SSL_HW_RECORD_ACCEL) + if( ssl_hw_record_reset != NULL) + { + SSL_DEBUG_MSG( 2, ( "going for ssl_hw_record_reset()" ) ); + if( ssl_hw_record_reset( ssl ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_hw_record_reset", ret ); + return( POLARSSL_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif + + if( ssl->transform ) + { + ssl_transform_free( ssl->transform ); + free( ssl->transform ); + ssl->transform = NULL; + } + + if( ssl->session ) + { + ssl_session_free( ssl->session ); + free( ssl->session ); + ssl->session = NULL; + } + + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * SSL set accessors + */ +void ssl_set_endpoint( ssl_context *ssl, int endpoint ) +{ + ssl->endpoint = endpoint; +} + +void ssl_set_authmode( ssl_context *ssl, int authmode ) +{ + ssl->authmode = authmode; +} + +void ssl_set_verify( ssl_context *ssl, + int (*f_vrfy)(void *, x509_cert *, int, int *), + void *p_vrfy ) +{ + ssl->f_vrfy = f_vrfy; + ssl->p_vrfy = p_vrfy; +} + +void ssl_set_rng( ssl_context *ssl, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + ssl->f_rng = f_rng; + ssl->p_rng = p_rng; +} + +void ssl_set_dbg( ssl_context *ssl, + void (*f_dbg)(void *, int, const char *), + void *p_dbg ) +{ + ssl->f_dbg = f_dbg; + ssl->p_dbg = p_dbg; +} + +void ssl_set_bio( ssl_context *ssl, + int (*f_recv)(void *, unsigned char *, size_t), void *p_recv, + int (*f_send)(void *, const unsigned char *, size_t), void *p_send ) +{ + ssl->f_recv = f_recv; + ssl->f_send = f_send; + ssl->p_recv = p_recv; + ssl->p_send = p_send; +} + +void ssl_set_session_cache( ssl_context *ssl, + int (*f_get_cache)(void *, ssl_session *), void *p_get_cache, + int (*f_set_cache)(void *, const ssl_session *), void *p_set_cache ) +{ + ssl->f_get_cache = f_get_cache; + ssl->p_get_cache = p_get_cache; + ssl->f_set_cache = f_set_cache; + ssl->p_set_cache = p_set_cache; +} + +void ssl_set_session( ssl_context *ssl, const ssl_session *session ) +{ + memcpy( ssl->session_negotiate, session, sizeof(ssl_session) ); + ssl->handshake->resume = 1; +} + +void ssl_set_ciphersuites( ssl_context *ssl, const int *ciphersuites ) +{ + ssl->ciphersuites[SSL_MINOR_VERSION_0] = ciphersuites; + ssl->ciphersuites[SSL_MINOR_VERSION_1] = ciphersuites; + ssl->ciphersuites[SSL_MINOR_VERSION_2] = ciphersuites; + ssl->ciphersuites[SSL_MINOR_VERSION_3] = ciphersuites; +} + +void ssl_set_ciphersuites_for_version( ssl_context *ssl, const int *ciphersuites, + int major, int minor ) +{ + if( major != SSL_MAJOR_VERSION_3 ) + return; + + if( minor < SSL_MINOR_VERSION_0 || minor > SSL_MINOR_VERSION_3 ) + return; + + ssl->ciphersuites[minor] = ciphersuites; +} + +void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain, + x509_crl *ca_crl, const char *peer_cn ) +{ + ssl->ca_chain = ca_chain; + ssl->ca_crl = ca_crl; + ssl->peer_cn = peer_cn; +} + +void ssl_set_own_cert( ssl_context *ssl, x509_cert *own_cert, + rsa_context *rsa_key ) +{ + ssl->own_cert = own_cert; + ssl->rsa_key = rsa_key; +} + +void ssl_set_own_cert_alt( ssl_context *ssl, x509_cert *own_cert, + void *rsa_key, + rsa_decrypt_func rsa_decrypt, + rsa_sign_func rsa_sign, + rsa_key_len_func rsa_key_len ) +{ + ssl->own_cert = own_cert; + ssl->rsa_key = rsa_key; + ssl->rsa_decrypt = rsa_decrypt; + ssl->rsa_sign = rsa_sign; + ssl->rsa_key_len = rsa_key_len; +} + + +#if defined(POLARSSL_DHM_C) +int ssl_set_dh_param( ssl_context *ssl, const char *dhm_P, const char *dhm_G ) +{ + int ret; + + if( ( ret = mpi_read_string( &ssl->dhm_P, 16, dhm_P ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "mpi_read_string", ret ); + return( ret ); + } + + if( ( ret = mpi_read_string( &ssl->dhm_G, 16, dhm_G ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "mpi_read_string", ret ); + return( ret ); + } + + return( 0 ); +} + +int ssl_set_dh_param_ctx( ssl_context *ssl, dhm_context *dhm_ctx ) +{ + int ret; + + if( ( ret = mpi_copy(&ssl->dhm_P, &dhm_ctx->P) ) != 0 ) + { + SSL_DEBUG_RET( 1, "mpi_copy", ret ); + return( ret ); + } + + if( ( ret = mpi_copy(&ssl->dhm_G, &dhm_ctx->G) ) != 0 ) + { + SSL_DEBUG_RET( 1, "mpi_copy", ret ); + return( ret ); + } + + return( 0 ); +} +#endif /* POLARSSL_DHM_C */ + +int ssl_set_hostname( ssl_context *ssl, const char *hostname ) +{ + if( hostname == NULL ) + return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + + ssl->hostname_len = strlen( hostname ); + ssl->hostname = (unsigned char *) malloc( ssl->hostname_len + 1 ); + + if( ssl->hostname == NULL ) + return( POLARSSL_ERR_SSL_MALLOC_FAILED ); + + memcpy( ssl->hostname, (const unsigned char *) hostname, + ssl->hostname_len ); + + ssl->hostname[ssl->hostname_len] = '\0'; + + return( 0 ); +} + +void ssl_set_sni( ssl_context *ssl, + int (*f_sni)(void *, ssl_context *, + const unsigned char *, size_t), + void *p_sni ) +{ + ssl->f_sni = f_sni; + ssl->p_sni = p_sni; +} + +void ssl_set_max_version( ssl_context *ssl, int major, int minor ) +{ + ssl->max_major_ver = major; + ssl->max_minor_ver = minor; +} + +void ssl_set_min_version( ssl_context *ssl, int major, int minor ) +{ + ssl->min_major_ver = major; + ssl->min_minor_ver = minor; +} + +void ssl_set_renegotiation( ssl_context *ssl, int renegotiation ) +{ + ssl->disable_renegotiation = renegotiation; +} + +void ssl_legacy_renegotiation( ssl_context *ssl, int allow_legacy ) +{ + ssl->allow_legacy_renegotiation = allow_legacy; +} + +/* + * SSL get accessors + */ +size_t ssl_get_bytes_avail( const ssl_context *ssl ) +{ + return( ssl->in_offt == NULL ? 0 : ssl->in_msglen ); +} + +int ssl_get_verify_result( const ssl_context *ssl ) +{ + return( ssl->verify_result ); +} + +const char *ssl_get_ciphersuite_name( const int ciphersuite_id ) +{ + switch( ciphersuite_id ) + { +#if defined(POLARSSL_ARC4_C) + case TLS_RSA_WITH_RC4_128_MD5: + return( "TLS-RSA-WITH-RC4-128-MD5" ); + + case TLS_RSA_WITH_RC4_128_SHA: + return( "TLS-RSA-WITH-RC4-128-SHA" ); +#endif + +#if defined(POLARSSL_DES_C) + case TLS_RSA_WITH_3DES_EDE_CBC_SHA: + return( "TLS-RSA-WITH-3DES-EDE-CBC-SHA" ); + + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + return( "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA" ); +#endif + +#if defined(POLARSSL_AES_C) + case TLS_RSA_WITH_AES_128_CBC_SHA: + return( "TLS-RSA-WITH-AES-128-CBC-SHA" ); + + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + return( "TLS-DHE-RSA-WITH-AES-128-CBC-SHA" ); + + case TLS_RSA_WITH_AES_256_CBC_SHA: + return( "TLS-RSA-WITH-AES-256-CBC-SHA" ); + + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + return( "TLS-DHE-RSA-WITH-AES-256-CBC-SHA" ); + +#if defined(POLARSSL_SHA2_C) + case TLS_RSA_WITH_AES_128_CBC_SHA256: + return( "TLS-RSA-WITH-AES-128-CBC-SHA256" ); + + case TLS_RSA_WITH_AES_256_CBC_SHA256: + return( "TLS-RSA-WITH-AES-256-CBC-SHA256" ); + + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: + return( "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256" ); + + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: + return( "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256" ); +#endif + +#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C) + case TLS_RSA_WITH_AES_128_GCM_SHA256: + return( "TLS-RSA-WITH-AES-128-GCM-SHA256" ); + + case TLS_RSA_WITH_AES_256_GCM_SHA384: + return( "TLS-RSA-WITH-AES-256-GCM-SHA384" ); +#endif + +#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C) + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: + return( "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256" ); + + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: + return( "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384" ); +#endif +#endif /* POLARSSL_AES_C */ + +#if defined(POLARSSL_CAMELLIA_C) + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: + return( "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA" ); + + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: + return( "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA" ); + + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: + return( "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA" ); + + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: + return( "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA" ); + +#if defined(POLARSSL_SHA2_C) + case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256: + return( "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256" ); + + case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: + return( "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256" ); + + case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: + return( "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256" ); + + case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: + return( "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256" ); +#endif +#endif + +#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) +#if defined(POLARSSL_CIPHER_NULL_CIPHER) + case TLS_RSA_WITH_NULL_MD5: + return( "TLS-RSA-WITH-NULL-MD5" ); + case TLS_RSA_WITH_NULL_SHA: + return( "TLS-RSA-WITH-NULL-SHA" ); + case TLS_RSA_WITH_NULL_SHA256: + return( "TLS-RSA-WITH-NULL-SHA256" ); +#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ + +#if defined(POLARSSL_DES_C) + case TLS_RSA_WITH_DES_CBC_SHA: + return( "TLS-RSA-WITH-DES-CBC-SHA" ); + case TLS_DHE_RSA_WITH_DES_CBC_SHA: + return( "TLS-DHE-RSA-WITH-DES-CBC-SHA" ); +#endif +#endif /* defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) */ + + default: + break; + } + + return( "unknown" ); +} + +int ssl_get_ciphersuite_id( const char *ciphersuite_name ) +{ +#if defined(POLARSSL_ARC4_C) + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-RC4-128-MD5")) + return( TLS_RSA_WITH_RC4_128_MD5 ); + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-RC4-128-SHA")) + return( TLS_RSA_WITH_RC4_128_SHA ); +#endif + +#if defined(POLARSSL_DES_C) + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-3DES-EDE-CBC-SHA")) + return( TLS_RSA_WITH_3DES_EDE_CBC_SHA ); + if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA")) + return( TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA ); +#endif + +#if defined(POLARSSL_AES_C) + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-AES-128-CBC-SHA")) + return( TLS_RSA_WITH_AES_128_CBC_SHA ); + if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-AES-128-CBC-SHA")) + return( TLS_DHE_RSA_WITH_AES_128_CBC_SHA ); + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-AES-256-CBC-SHA")) + return( TLS_RSA_WITH_AES_256_CBC_SHA ); + if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-AES-256-CBC-SHA")) + return( TLS_DHE_RSA_WITH_AES_256_CBC_SHA ); + +#if defined(POLARSSL_SHA2_C) + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-AES-128-CBC-SHA256")) + return( TLS_RSA_WITH_AES_128_CBC_SHA256 ); + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-AES-256-CBC-SHA256")) + return( TLS_RSA_WITH_AES_256_CBC_SHA256 ); + if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256")) + return( TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ); + if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256")) + return( TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ); +#endif + +#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C) + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-AES-128-GCM-SHA256")) + return( TLS_RSA_WITH_AES_128_GCM_SHA256 ); + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-AES-256-GCM-SHA384")) + return( TLS_RSA_WITH_AES_256_GCM_SHA384 ); +#endif + +#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C) + if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256")) + return( TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ); + if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384")) + return( TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ); +#endif +#endif + +#if defined(POLARSSL_CAMELLIA_C) + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA")) + return( TLS_RSA_WITH_CAMELLIA_128_CBC_SHA ); + if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA")) + return( TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA ); + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA")) + return( TLS_RSA_WITH_CAMELLIA_256_CBC_SHA ); + if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA")) + return( TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA ); + +#if defined(POLARSSL_SHA2_C) + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256")) + return( TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 ); + if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256")) + return( TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 ); + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256")) + return( TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 ); + if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256")) + return( TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 ); +#endif +#endif + +#if defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) +#if defined(POLARSSL_CIPHER_NULL_CIPHER) + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-NULL-MD5")) + return( TLS_RSA_WITH_NULL_MD5 ); + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-NULL-SHA")) + return( TLS_RSA_WITH_NULL_SHA ); + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-NULL-SHA256")) + return( TLS_RSA_WITH_NULL_SHA256 ); +#endif /* defined(POLARSSL_CIPHER_NULL_CIPHER) */ + +#if defined(POLARSSL_DES_C) + if (0 == strcasecmp(ciphersuite_name, "TLS-RSA-WITH-DES-CBC-SHA")) + return( TLS_RSA_WITH_DES_CBC_SHA ); + if (0 == strcasecmp(ciphersuite_name, "TLS-DHE-RSA-WITH-DES-CBC-SHA")) + return( TLS_DHE_RSA_WITH_DES_CBC_SHA ); +#endif +#endif /* defined(POLARSSL_ENABLE_WEAK_CIPHERSUITES) */ + + return( 0 ); +} + +const char *ssl_get_ciphersuite( const ssl_context *ssl ) +{ + if( ssl == NULL || ssl->session == NULL ) + return NULL; + + return ssl_get_ciphersuite_name( ssl->session->ciphersuite ); +} + +const char *ssl_get_version( const ssl_context *ssl ) +{ + switch( ssl->minor_ver ) + { + case SSL_MINOR_VERSION_0: + return( "SSLv3.0" ); + + case SSL_MINOR_VERSION_1: + return( "TLSv1.0" ); + + case SSL_MINOR_VERSION_2: + return( "TLSv1.1" ); + + case SSL_MINOR_VERSION_3: + return( "TLSv1.2" ); + + default: + break; + } + return( "unknown" ); +} + +const x509_cert *ssl_get_peer_cert( const ssl_context *ssl ) +{ + if( ssl == NULL || ssl->session == NULL ) + return NULL; + + return ssl->session->peer_cert; +} + +const int ssl_default_ciphersuites[] = +{ +#if defined(POLARSSL_DHM_C) +#if defined(POLARSSL_AES_C) +#if defined(POLARSSL_SHA2_C) + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, +#endif /* POLARSSL_SHA2_C */ +#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C) + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, +#endif + TLS_DHE_RSA_WITH_AES_256_CBC_SHA, +#if defined(POLARSSL_SHA2_C) + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, +#endif +#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C) + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, +#endif + TLS_DHE_RSA_WITH_AES_128_CBC_SHA, +#endif +#if defined(POLARSSL_CAMELLIA_C) +#if defined(POLARSSL_SHA2_C) + TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, +#endif /* POLARSSL_SHA2_C */ + TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, +#if defined(POLARSSL_SHA2_C) + TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, +#endif /* POLARSSL_SHA2_C */ + TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, +#endif +#if defined(POLARSSL_DES_C) + TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, +#endif +#endif + +#if defined(POLARSSL_AES_C) +#if defined(POLARSSL_SHA2_C) + TLS_RSA_WITH_AES_256_CBC_SHA256, +#endif /* POLARSSL_SHA2_C */ +#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA4_C) + TLS_RSA_WITH_AES_256_GCM_SHA384, +#endif /* POLARSSL_SHA2_C */ + TLS_RSA_WITH_AES_256_CBC_SHA, +#endif +#if defined(POLARSSL_CAMELLIA_C) +#if defined(POLARSSL_SHA2_C) + TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, +#endif /* POLARSSL_SHA2_C */ + TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, +#endif +#if defined(POLARSSL_AES_C) +#if defined(POLARSSL_SHA2_C) + TLS_RSA_WITH_AES_128_CBC_SHA256, +#endif /* POLARSSL_SHA2_C */ +#if defined(POLARSSL_GCM_C) && defined(POLARSSL_SHA2_C) + TLS_RSA_WITH_AES_128_GCM_SHA256, +#endif /* POLARSSL_SHA2_C */ + TLS_RSA_WITH_AES_128_CBC_SHA, +#endif +#if defined(POLARSSL_CAMELLIA_C) +#if defined(POLARSSL_SHA2_C) + TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, +#endif /* POLARSSL_SHA2_C */ + TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, +#endif +#if defined(POLARSSL_DES_C) + TLS_RSA_WITH_3DES_EDE_CBC_SHA, +#endif +#if defined(POLARSSL_ARC4_C) + TLS_RSA_WITH_RC4_128_SHA, + TLS_RSA_WITH_RC4_128_MD5, +#endif + 0 +}; + +/* + * Perform a single step of the SSL handshake + */ +int ssl_handshake_step( ssl_context *ssl ) +{ + int ret = POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE; + +#if defined(POLARSSL_SSL_CLI_C) + if( ssl->endpoint == SSL_IS_CLIENT ) + ret = ssl_handshake_client_step( ssl ); +#endif + +#if defined(POLARSSL_SSL_SRV_C) + if( ssl->endpoint == SSL_IS_SERVER ) + ret = ssl_handshake_server_step( ssl ); +#endif + + return( ret ); +} + +/* + * Perform the SSL handshake + */ +int ssl_handshake( ssl_context *ssl ) +{ + int ret = 0; + + SSL_DEBUG_MSG( 2, ( "=> handshake" ) ); + + while( ssl->state != SSL_HANDSHAKE_OVER ) + { + ret = ssl_handshake_step( ssl ); + + if( ret != 0 ) + break; + } + + SSL_DEBUG_MSG( 2, ( "<= handshake" ) ); + + return( ret ); +} + +/* + * Renegotiate current connection + */ +int ssl_renegotiate( ssl_context *ssl ) +{ + int ret; + + SSL_DEBUG_MSG( 2, ( "=> renegotiate" ) ); + + if( ssl->state != SSL_HANDSHAKE_OVER ) + return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + + ssl->state = SSL_HELLO_REQUEST; + ssl->renegotiation = SSL_RENEGOTIATION; + + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) + return( ret ); + + if( ( ret = ssl_handshake( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_handshake", ret ); + return( ret ); + } + + SSL_DEBUG_MSG( 2, ( "<= renegotiate" ) ); + + return( 0 ); +} + +/* + * Receive application data decrypted from the SSL layer + */ +int ssl_read( ssl_context *ssl, unsigned char *buf, size_t len ) +{ + int ret; + size_t n; + + SSL_DEBUG_MSG( 2, ( "=> read" ) ); + + if( ssl->state != SSL_HANDSHAKE_OVER ) + { + if( ( ret = ssl_handshake( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_handshake", ret ); + return( ret ); + } + } + + if( ssl->in_offt == NULL ) + { + if( ( ret = ssl_read_record( ssl ) ) != 0 ) + { + if( ret == POLARSSL_ERR_SSL_CONN_EOF ) + return( 0 ); + + SSL_DEBUG_RET( 1, "ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msglen == 0 && + ssl->in_msgtype == SSL_MSG_APPLICATION_DATA ) + { + /* + * OpenSSL sends empty messages to randomize the IV + */ + if( ( ret = ssl_read_record( ssl ) ) != 0 ) + { + if( ret == POLARSSL_ERR_SSL_CONN_EOF ) + return( 0 ); + + SSL_DEBUG_RET( 1, "ssl_read_record", ret ); + return( ret ); + } + } + + if( ssl->in_msgtype == SSL_MSG_HANDSHAKE ) + { + SSL_DEBUG_MSG( 1, ( "received handshake message" ) ); + + if( ssl->endpoint == SSL_IS_CLIENT && + ( ssl->in_msg[0] != SSL_HS_HELLO_REQUEST || + ssl->in_hslen != 4 ) ) + { + SSL_DEBUG_MSG( 1, ( "handshake received (not HelloRequest)" ) ); + return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->disable_renegotiation == SSL_RENEGOTIATION_DISABLED || + ( ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && + ssl->allow_legacy_renegotiation == SSL_LEGACY_NO_RENEGOTIATION ) ) + { + SSL_DEBUG_MSG( 3, ( "ignoring renegotiation, sending alert" ) ); + + if( ssl->minor_ver == SSL_MINOR_VERSION_0 ) + { + /* + * SSLv3 does not have a "no_renegotiation" alert + */ + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + } + else + { + if( ( ret = ssl_send_alert_message( ssl, + SSL_ALERT_LEVEL_WARNING, + SSL_ALERT_MSG_NO_RENEGOTIATION ) ) != 0 ) + { + return( ret ); + } + } + } + else + { + if( ( ret = ssl_renegotiate( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_renegotiate", ret ); + return( ret ); + } + + return( POLARSSL_ERR_NET_WANT_READ ); + } + } + else if( ssl->in_msgtype != SSL_MSG_APPLICATION_DATA ) + { + SSL_DEBUG_MSG( 1, ( "bad application data message" ) ); + return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + ssl->in_offt = ssl->in_msg; + } + + n = ( len < ssl->in_msglen ) + ? len : ssl->in_msglen; + + memcpy( buf, ssl->in_offt, n ); + ssl->in_msglen -= n; + + if( ssl->in_msglen == 0 ) + /* all bytes consumed */ + ssl->in_offt = NULL; + else + /* more data available */ + ssl->in_offt += n; + + SSL_DEBUG_MSG( 2, ( "<= read" ) ); + + return( (int) n ); +} + +/* + * Send application data to be encrypted by the SSL layer + */ +int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len ) +{ + int ret; + size_t n; + + SSL_DEBUG_MSG( 2, ( "=> write" ) ); + + if( ssl->state != SSL_HANDSHAKE_OVER ) + { + if( ( ret = ssl_handshake( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_handshake", ret ); + return( ret ); + } + } + + n = ( len < SSL_MAX_CONTENT_LEN ) + ? len : SSL_MAX_CONTENT_LEN; + + if( ssl->out_left != 0 ) + { + if( ( ret = ssl_flush_output( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_flush_output", ret ); + return( ret ); + } + } + else + { + ssl->out_msglen = n; + ssl->out_msgtype = SSL_MSG_APPLICATION_DATA; + memcpy( ssl->out_msg, buf, n ); + + if( ( ret = ssl_write_record( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + } + + SSL_DEBUG_MSG( 2, ( "<= write" ) ); + + return( (int) n ); +} + +/* + * Notify the peer that the connection is being closed + */ +int ssl_close_notify( ssl_context *ssl ) +{ + int ret; + + SSL_DEBUG_MSG( 2, ( "=> write close notify" ) ); + + if( ( ret = ssl_flush_output( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_flush_output", ret ); + return( ret ); + } + + if( ssl->state == SSL_HANDSHAKE_OVER ) + { + if( ( ret = ssl_send_alert_message( ssl, + SSL_ALERT_LEVEL_WARNING, + SSL_ALERT_MSG_CLOSE_NOTIFY ) ) != 0 ) + { + return( ret ); + } + } + + SSL_DEBUG_MSG( 2, ( "<= write close notify" ) ); + + return( ret ); +} + +void ssl_transform_free( ssl_transform *transform ) +{ +#if defined(POLARSSL_ZLIB_SUPPORT) + deflateEnd( &transform->ctx_deflate ); + inflateEnd( &transform->ctx_inflate ); +#endif + + memset( transform, 0, sizeof( ssl_transform ) ); +} + +void ssl_handshake_free( ssl_handshake_params *handshake ) +{ +#if defined(POLARSSL_DHM_C) + dhm_free( &handshake->dhm_ctx ); +#endif + memset( handshake, 0, sizeof( ssl_handshake_params ) ); +} + +void ssl_session_free( ssl_session *session ) +{ + if( session->peer_cert != NULL ) + { + x509_free( session->peer_cert ); + free( session->peer_cert ); + } + + memset( session, 0, sizeof( ssl_session ) ); +} + +/* + * Free an SSL context + */ +void ssl_free( ssl_context *ssl ) +{ + SSL_DEBUG_MSG( 2, ( "=> free" ) ); + + free( ssl->ciphersuites ); + + if( ssl->out_ctr != NULL ) + { + memset( ssl->out_ctr, 0, SSL_BUFFER_LEN ); + free( ssl->out_ctr ); + } + + if( ssl->in_ctr != NULL ) + { + memset( ssl->in_ctr, 0, SSL_BUFFER_LEN ); + free( ssl->in_ctr ); + } + +#if defined(POLARSSL_DHM_C) + mpi_free( &ssl->dhm_P ); + mpi_free( &ssl->dhm_G ); +#endif + + if( ssl->transform ) + { + ssl_transform_free( ssl->transform ); + free( ssl->transform ); + } + + if( ssl->handshake ) + { + ssl_handshake_free( ssl->handshake ); + ssl_transform_free( ssl->transform_negotiate ); + ssl_session_free( ssl->session_negotiate ); + + free( ssl->handshake ); + free( ssl->transform_negotiate ); + free( ssl->session_negotiate ); + } + + if( ssl->session ) + { + ssl_session_free( ssl->session ); + free( ssl->session ); + } + + if ( ssl->hostname != NULL) + { + memset( ssl->hostname, 0, ssl->hostname_len ); + free( ssl->hostname ); + ssl->hostname_len = 0; + } + +#if defined(POLARSSL_SSL_HW_RECORD_ACCEL) + if( ssl_hw_record_finish != NULL ) + { + SSL_DEBUG_MSG( 2, ( "going for ssl_hw_record_finish()" ) ); + ssl_hw_record_finish( ssl ); + } +#endif + + SSL_DEBUG_MSG( 2, ( "<= free" ) ); + + /* Actually clear after last debug message */ + memset( ssl, 0, sizeof( ssl_context ) ); +} + +#endif diff --git a/src/libpolarssl/timing.c b/src/libpolarssl/timing.c new file mode 100644 index 0000000..f44db83 --- /dev/null +++ b/src/libpolarssl/timing.c @@ -0,0 +1,312 @@ +/* + * Portable interface to the CPU cycle counter + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_TIMING_C) + +#include "timing.h" + +#if defined(_WIN32) + +#include +#include + +struct _hr_time +{ + LARGE_INTEGER start; +}; + +#else + +#include +#include +#include +#include +#include + +struct _hr_time +{ + struct timeval start; +}; + +#endif + +#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ + (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + +#define POLARSSL_HAVE_HARDCLOCK + +unsigned long hardclock( void ) +{ + unsigned long tsc; + __asm rdtsc + __asm mov [tsc], eax + return( tsc ); +} +#endif + +#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ + defined(__GNUC__) && defined(__i386__) + +#define POLARSSL_HAVE_HARDCLOCK + +unsigned long hardclock( void ) +{ + unsigned long lo, hi; + asm( "rdtsc" : "=a" (lo), "=d" (hi) ); + return( lo ); +} +#endif + +#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ + defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__)) + +#define POLARSSL_HAVE_HARDCLOCK + +unsigned long hardclock( void ) +{ + unsigned long lo, hi; + asm( "rdtsc" : "=a" (lo), "=d" (hi) ); + return( lo | (hi << 32) ); +} +#endif + +#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ + defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__)) + +#define POLARSSL_HAVE_HARDCLOCK + +unsigned long hardclock( void ) +{ + unsigned long tbl, tbu0, tbu1; + + do + { + asm( "mftbu %0" : "=r" (tbu0) ); + asm( "mftb %0" : "=r" (tbl ) ); + asm( "mftbu %0" : "=r" (tbu1) ); + } + while( tbu0 != tbu1 ); + + return( tbl ); +} +#endif + +#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ + defined(__GNUC__) && defined(__sparc64__) + +#if defined(__OpenBSD__) +#warning OpenBSD does not allow access to tick register using software version instead +#else +#define POLARSSL_HAVE_HARDCLOCK + +unsigned long hardclock( void ) +{ + unsigned long tick; + asm( "rdpr %%tick, %0;" : "=&r" (tick) ); + return( tick ); +} +#endif +#endif + +#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ + defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__) + +#define POLARSSL_HAVE_HARDCLOCK + +unsigned long hardclock( void ) +{ + unsigned long tick; + asm( ".byte 0x83, 0x41, 0x00, 0x00" ); + asm( "mov %%g1, %0" : "=r" (tick) ); + return( tick ); +} +#endif + +#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ + defined(__GNUC__) && defined(__alpha__) + +#define POLARSSL_HAVE_HARDCLOCK + +unsigned long hardclock( void ) +{ + unsigned long cc; + asm( "rpcc %0" : "=r" (cc) ); + return( cc & 0xFFFFFFFF ); +} +#endif + +#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ + defined(__GNUC__) && defined(__ia64__) + +#define POLARSSL_HAVE_HARDCLOCK + +unsigned long hardclock( void ) +{ + unsigned long itc; + asm( "mov %0 = ar.itc" : "=r" (itc) ); + return( itc ); +} +#endif + +#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(_MSC_VER) + +#define POLARSSL_HAVE_HARDCLOCK + +unsigned long hardclock( void ) +{ + LARGE_INTEGER offset; + + QueryPerformanceCounter( &offset ); + + return (unsigned long)( offset.QuadPart ); +} +#endif + +#if !defined(POLARSSL_HAVE_HARDCLOCK) + +#define POLARSSL_HAVE_HARDCLOCK + +static int hardclock_init = 0; +static struct timeval tv_init; + +unsigned long hardclock( void ) +{ + struct timeval tv_cur; + + if( hardclock_init == 0 ) + { + gettimeofday( &tv_init, NULL ); + hardclock_init = 1; + } + + gettimeofday( &tv_cur, NULL ); + return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000 + + ( tv_cur.tv_usec - tv_init.tv_usec ) ); +} +#endif + +volatile int alarmed = 0; + +#if defined(_WIN32) + +unsigned long get_timer( struct hr_time *val, int reset ) +{ + unsigned long delta; + LARGE_INTEGER offset, hfreq; + struct _hr_time *t = (struct _hr_time *) val; + + QueryPerformanceCounter( &offset ); + QueryPerformanceFrequency( &hfreq ); + + delta = (unsigned long)( ( 1000 * + ( offset.QuadPart - t->start.QuadPart ) ) / + hfreq.QuadPart ); + + if( reset ) + QueryPerformanceCounter( &t->start ); + + return( delta ); +} + +DWORD WINAPI TimerProc( LPVOID uElapse ) +{ + Sleep( (DWORD) uElapse ); + alarmed = 1; + return( TRUE ); +} + +void set_alarm( int seconds ) +{ + DWORD ThreadId; + + alarmed = 0; + CloseHandle( CreateThread( NULL, 0, TimerProc, + (LPVOID) ( seconds * 1000 ), 0, &ThreadId ) ); +} + +void m_sleep( int milliseconds ) +{ + Sleep( milliseconds ); +} + +#else + +unsigned long get_timer( struct hr_time *val, int reset ) +{ + unsigned long delta; + struct timeval offset; + struct _hr_time *t = (struct _hr_time *) val; + + gettimeofday( &offset, NULL ); + + delta = ( offset.tv_sec - t->start.tv_sec ) * 1000 + + ( offset.tv_usec - t->start.tv_usec ) / 1000; + + if( reset ) + { + t->start.tv_sec = offset.tv_sec; + t->start.tv_usec = offset.tv_usec; + } + + return( delta ); +} + +#if defined(INTEGRITY) +void m_sleep( int milliseconds ) +{ + usleep( milliseconds * 1000 ); +} + +#else + +static void sighandler( int signum ) +{ + alarmed = 1; + signal( signum, sighandler ); +} + +void set_alarm( int seconds ) +{ + alarmed = 0; + signal( SIGALRM, sighandler ); + alarm( seconds ); +} + +void m_sleep( int milliseconds ) +{ + struct timeval tv; + + tv.tv_sec = milliseconds / 1000; + tv.tv_usec = milliseconds * 1000; + + select( 0, NULL, NULL, NULL, &tv ); +} +#endif /* INTEGRITY */ + +#endif + +#endif diff --git a/src/libpolarssl/timing.h b/src/libpolarssl/timing.h new file mode 100644 index 0000000..355c63c --- /dev/null +++ b/src/libpolarssl/timing.h @@ -0,0 +1,75 @@ +/** + * \file timing.h + * + * \brief Portable interface to the CPU cycle counter + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_TIMING_H +#define POLARSSL_TIMING_H + +/** + * \brief timer structure + */ +struct hr_time +{ + unsigned char opaque[32]; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern volatile int alarmed; + +/** + * \brief Return the CPU cycle counter value + */ +unsigned long hardclock( void ); + +/** + * \brief Return the elapsed time in milliseconds + * + * \param val points to a timer structure + * \param reset if set to 1, the timer is restarted + */ +unsigned long get_timer( struct hr_time *val, int reset ); + +/** + * \brief Setup an alarm clock + * + * \param seconds delay before the "alarmed" flag is set + */ +void set_alarm( int seconds ); + +/** + * \brief Sleep for a certain amount of time + * + * \param milliseconds delay in milliseconds + */ +void m_sleep( int milliseconds ); + +#ifdef __cplusplus +} +#endif + +#endif /* timing.h */ diff --git a/src/libpolarssl/version.c b/src/libpolarssl/version.c new file mode 100644 index 0000000..9927382 --- /dev/null +++ b/src/libpolarssl/version.c @@ -0,0 +1,50 @@ +/* + * Version information + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_VERSION_C) + +#include "version.h" +#include + +const char version[] = POLARSSL_VERSION_STRING; + +unsigned int version_get_number() +{ + return POLARSSL_VERSION_NUMBER; +} + +void version_get_string( char *string ) +{ + memcpy( string, POLARSSL_VERSION_STRING, sizeof( POLARSSL_VERSION_STRING ) ); +} + +void version_get_string_full( char *string ) +{ + memcpy( string, POLARSSL_VERSION_STRING_FULL, sizeof( POLARSSL_VERSION_STRING_FULL ) ); +} + +#endif /* POLARSSL_VERSION_C */ diff --git a/src/libpolarssl/version.h b/src/libpolarssl/version.h new file mode 100644 index 0000000..036e2b4 --- /dev/null +++ b/src/libpolarssl/version.h @@ -0,0 +1,81 @@ +/** + * \file version.h + * + * \brief Run-time version information + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * This set of compile-time defines and run-time variables can be used to + * determine the version number of the PolarSSL library used. + */ +#ifndef POLARSSL_VERSION_H +#define POLARSSL_VERSION_H + +#include "config.h" + +/** + * The version number x.y.z is split into three parts. + * Major, Minor, Patchlevel + */ +#define POLARSSL_VERSION_MAJOR 1 +#define POLARSSL_VERSION_MINOR 2 +#define POLARSSL_VERSION_PATCH 8 + +/** + * The single version number has the following structure: + * MMNNPP00 + * Major version | Minor version | Patch version + */ +#define POLARSSL_VERSION_NUMBER 0x01020800 +#define POLARSSL_VERSION_STRING "1.2.8" +#define POLARSSL_VERSION_STRING_FULL "PolarSSL 1.2.8" + +#if defined(POLARSSL_VERSION_C) + +/** + * Get the version number. + * + * \return The constructed version number in the format + * MMNNPP00 (Major, Minor, Patch). + */ +unsigned int version_get_number( void ); + +/** + * Get the version string ("x.y.z"). + * + * \param string The string that will receive the value. + * (Should be at least 9 bytes in size) + */ +void version_get_string( char *string ); + +/** + * Get the full version string ("PolarSSL x.y.z"). + * + * \param string The string that will receive the value. + * (Should be at least 18 bytes in size) + */ +void version_get_string_full( char *string ); + +#endif /* POLARSSL_VERSION_C */ + +#endif /* version.h */ diff --git a/src/libpolarssl/x509.h b/src/libpolarssl/x509.h new file mode 100644 index 0000000..b4ebf64 --- /dev/null +++ b/src/libpolarssl/x509.h @@ -0,0 +1,776 @@ +/** + * \file x509.h + * + * \brief X.509 certificate and private key decoding + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_X509_H +#define POLARSSL_X509_H + +#include "asn1.h" +#include "rsa.h" +#include "dhm.h" + +/** + * \addtogroup x509_module + * \{ + */ + +/** + * \name X509 Error codes + * \{ + */ +#define POLARSSL_ERR_X509_FEATURE_UNAVAILABLE -0x2080 /**< Unavailable feature, e.g. RSA hashing/encryption combination. */ +#define POLARSSL_ERR_X509_CERT_INVALID_PEM -0x2100 /**< The PEM-encoded certificate contains invalid elements, e.g. invalid character. */ +#define POLARSSL_ERR_X509_CERT_INVALID_FORMAT -0x2180 /**< The certificate format is invalid, e.g. different type expected. */ +#define POLARSSL_ERR_X509_CERT_INVALID_VERSION -0x2200 /**< The certificate version element is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_SERIAL -0x2280 /**< The serial tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_ALG -0x2300 /**< The algorithm tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_NAME -0x2380 /**< The name tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_DATE -0x2400 /**< The date tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_PUBKEY -0x2480 /**< The pubkey tag or value is invalid (only RSA is supported). */ +#define POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE -0x2500 /**< The signature tag or value invalid. */ +#define POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS -0x2580 /**< The extension tag or value is invalid. */ +#define POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION -0x2600 /**< Certificate or CRL has an unsupported version number. */ +#define POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG -0x2680 /**< Signature algorithm (oid) is unsupported. */ +#define POLARSSL_ERR_X509_UNKNOWN_PK_ALG -0x2700 /**< Key algorithm is unsupported (only RSA is supported). */ +#define POLARSSL_ERR_X509_CERT_SIG_MISMATCH -0x2780 /**< Certificate signature algorithms do not match. (see \c ::x509_cert sig_oid) */ +#define POLARSSL_ERR_X509_CERT_VERIFY_FAILED -0x2800 /**< Certificate verification failed, e.g. CRL, CA or signature check failed. */ +#define POLARSSL_ERR_X509_KEY_INVALID_VERSION -0x2880 /**< Unsupported RSA key version */ +#define POLARSSL_ERR_X509_KEY_INVALID_FORMAT -0x2900 /**< Invalid RSA key tag or value. */ +#define POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT -0x2980 /**< Format not recognized as DER or PEM. */ +#define POLARSSL_ERR_X509_INVALID_INPUT -0x2A00 /**< Input invalid. */ +#define POLARSSL_ERR_X509_MALLOC_FAILED -0x2A80 /**< Allocation of memory failed. */ +#define POLARSSL_ERR_X509_FILE_IO_ERROR -0x2B00 /**< Read/write of file failed. */ +#define POLARSSL_ERR_X509_PASSWORD_REQUIRED -0x2B80 /**< Private key password can't be empty. */ +#define POLARSSL_ERR_X509_PASSWORD_MISMATCH -0x2C00 /**< Given private key password does not allow for correct decryption. */ +/* \} name */ + + +/** + * \name X509 Verify codes + * \{ + */ +#define BADCERT_EXPIRED 0x01 /**< The certificate validity has expired. */ +#define BADCERT_REVOKED 0x02 /**< The certificate has been revoked (is on a CRL). */ +#define BADCERT_CN_MISMATCH 0x04 /**< The certificate Common Name (CN) does not match with the expected CN. */ +#define BADCERT_NOT_TRUSTED 0x08 /**< The certificate is not correctly signed by the trusted CA. */ +#define BADCRL_NOT_TRUSTED 0x10 /**< CRL is not correctly signed by the trusted CA. */ +#define BADCRL_EXPIRED 0x20 /**< CRL is expired. */ +#define BADCERT_MISSING 0x40 /**< Certificate was missing. */ +#define BADCERT_SKIP_VERIFY 0x80 /**< Certificate verification was skipped. */ +#define BADCERT_OTHER 0x0100 /**< Other reason (can be used by verify callback) */ +/* \} name */ +/* \} addtogroup x509_module */ + +/* + * various object identifiers + */ +#define X520_COMMON_NAME 3 +#define X520_COUNTRY 6 +#define X520_LOCALITY 7 +#define X520_STATE 8 +#define X520_ORGANIZATION 10 +#define X520_ORG_UNIT 11 +#define PKCS9_EMAIL 1 + +#define X509_OUTPUT_DER 0x01 +#define X509_OUTPUT_PEM 0x02 +#define PEM_LINE_LENGTH 72 +#define X509_ISSUER 0x01 +#define X509_SUBJECT 0x02 + +#define OID_X520 "\x55\x04" +#define OID_CN OID_X520 "\x03" +#define OID_COUNTRY OID_X520 "\x06" +#define OID_LOCALITY OID_X520 "\x07" +#define OID_STATE OID_X520 "\x08" +#define OID_ORGANIZATION OID_X520 "\x0A" +#define OID_ORG_UNIT OID_X520 "\x0B" + +#define OID_PKCS1 "\x2A\x86\x48\x86\xF7\x0D\x01\x01" +#define OID_PKCS1_RSA OID_PKCS1 "\x01" +#define OID_PKCS1_SHA1 OID_PKCS1 "\x05" + +#define OID_RSA_SHA_OBS "\x2B\x0E\x03\x02\x1D" + +#define OID_PKCS9 "\x2A\x86\x48\x86\xF7\x0D\x01\x09" +#define OID_PKCS9_EMAIL OID_PKCS9 "\x01" + +/** ISO arc for standard certificate and CRL extensions */ +#define OID_ID_CE "\x55\x1D" /**< id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} */ + +/** + * Private Internet Extensions + * { iso(1) identified-organization(3) dod(6) internet(1) + * security(5) mechanisms(5) pkix(7) } + */ +#define OID_PKIX "\x2B\x06\x01\x05\x05\x07" + +/* + * OIDs for standard certificate extensions + */ +#define OID_AUTHORITY_KEY_IDENTIFIER OID_ID_CE "\x23" /**< id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } */ +#define OID_SUBJECT_KEY_IDENTIFIER OID_ID_CE "\x0E" /**< id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 } */ +#define OID_KEY_USAGE OID_ID_CE "\x0F" /**< id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } */ +#define OID_CERTIFICATE_POLICIES OID_ID_CE "\x20" /**< id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } */ +#define OID_POLICY_MAPPINGS OID_ID_CE "\x21" /**< id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } */ +#define OID_SUBJECT_ALT_NAME OID_ID_CE "\x11" /**< id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } */ +#define OID_ISSUER_ALT_NAME OID_ID_CE "\x12" /**< id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 } */ +#define OID_SUBJECT_DIRECTORY_ATTRS OID_ID_CE "\x09" /**< id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 } */ +#define OID_BASIC_CONSTRAINTS OID_ID_CE "\x13" /**< id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } */ +#define OID_NAME_CONSTRAINTS OID_ID_CE "\x1E" /**< id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 } */ +#define OID_POLICY_CONSTRAINTS OID_ID_CE "\x24" /**< id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 } */ +#define OID_EXTENDED_KEY_USAGE OID_ID_CE "\x25" /**< id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } */ +#define OID_CRL_DISTRIBUTION_POINTS OID_ID_CE "\x1F" /**< id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 } */ +#define OID_INIHIBIT_ANYPOLICY OID_ID_CE "\x36" /**< id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 } */ +#define OID_FRESHEST_CRL OID_ID_CE "\x2E" /**< id-ce-freshestCRL OBJECT IDENTIFIER ::= { id-ce 46 } */ + +/* + * X.509 v3 Key Usage Extension flags + */ +#define KU_DIGITAL_SIGNATURE (0x80) /* bit 0 */ +#define KU_NON_REPUDIATION (0x40) /* bit 1 */ +#define KU_KEY_ENCIPHERMENT (0x20) /* bit 2 */ +#define KU_DATA_ENCIPHERMENT (0x10) /* bit 3 */ +#define KU_KEY_AGREEMENT (0x08) /* bit 4 */ +#define KU_KEY_CERT_SIGN (0x04) /* bit 5 */ +#define KU_CRL_SIGN (0x02) /* bit 6 */ + +/* + * X.509 v3 Extended key usage OIDs + */ +#define OID_ANY_EXTENDED_KEY_USAGE OID_EXTENDED_KEY_USAGE "\x00" /**< anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } */ + +#define OID_KP OID_PKIX "\x03" /**< id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } */ +#define OID_SERVER_AUTH OID_KP "\x01" /**< id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } */ +#define OID_CLIENT_AUTH OID_KP "\x02" /**< id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } */ +#define OID_CODE_SIGNING OID_KP "\x03" /**< id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } */ +#define OID_EMAIL_PROTECTION OID_KP "\x04" /**< id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } */ +#define OID_TIME_STAMPING OID_KP "\x08" /**< id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } */ +#define OID_OCSP_SIGNING OID_KP "\x09" /**< id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } */ + +#define STRING_SERVER_AUTH "TLS Web Server Authentication" +#define STRING_CLIENT_AUTH "TLS Web Client Authentication" +#define STRING_CODE_SIGNING "Code Signing" +#define STRING_EMAIL_PROTECTION "E-mail Protection" +#define STRING_TIME_STAMPING "Time Stamping" +#define STRING_OCSP_SIGNING "OCSP Signing" + +/* + * OIDs for CRL extensions + */ +#define OID_PRIVATE_KEY_USAGE_PERIOD OID_ID_CE "\x10" +#define OID_CRL_NUMBER OID_ID_CE "\x14" /**< id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 } */ + +/* + * Netscape certificate extensions + */ +#define OID_NETSCAPE "\x60\x86\x48\x01\x86\xF8\x42" /**< Netscape OID */ +#define OID_NS_CERT OID_NETSCAPE "\x01" +#define OID_NS_CERT_TYPE OID_NS_CERT "\x01" +#define OID_NS_BASE_URL OID_NS_CERT "\x02" +#define OID_NS_REVOCATION_URL OID_NS_CERT "\x03" +#define OID_NS_CA_REVOCATION_URL OID_NS_CERT "\x04" +#define OID_NS_RENEWAL_URL OID_NS_CERT "\x07" +#define OID_NS_CA_POLICY_URL OID_NS_CERT "\x08" +#define OID_NS_SSL_SERVER_NAME OID_NS_CERT "\x0C" +#define OID_NS_COMMENT OID_NS_CERT "\x0D" +#define OID_NS_DATA_TYPE OID_NETSCAPE "\x02" +#define OID_NS_CERT_SEQUENCE OID_NS_DATA_TYPE "\x05" + +/* + * Netscape certificate types + * (http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html) + */ + +#define NS_CERT_TYPE_SSL_CLIENT (0x80) /* bit 0 */ +#define NS_CERT_TYPE_SSL_SERVER (0x40) /* bit 1 */ +#define NS_CERT_TYPE_EMAIL (0x20) /* bit 2 */ +#define NS_CERT_TYPE_OBJECT_SIGNING (0x10) /* bit 3 */ +#define NS_CERT_TYPE_RESERVED (0x08) /* bit 4 */ +#define NS_CERT_TYPE_SSL_CA (0x04) /* bit 5 */ +#define NS_CERT_TYPE_EMAIL_CA (0x02) /* bit 6 */ +#define NS_CERT_TYPE_OBJECT_SIGNING_CA (0x01) /* bit 7 */ + +#define EXT_AUTHORITY_KEY_IDENTIFIER (1 << 0) +#define EXT_SUBJECT_KEY_IDENTIFIER (1 << 1) +#define EXT_KEY_USAGE (1 << 2) +#define EXT_CERTIFICATE_POLICIES (1 << 3) +#define EXT_POLICY_MAPPINGS (1 << 4) +#define EXT_SUBJECT_ALT_NAME (1 << 5) +#define EXT_ISSUER_ALT_NAME (1 << 6) +#define EXT_SUBJECT_DIRECTORY_ATTRS (1 << 7) +#define EXT_BASIC_CONSTRAINTS (1 << 8) +#define EXT_NAME_CONSTRAINTS (1 << 9) +#define EXT_POLICY_CONSTRAINTS (1 << 10) +#define EXT_EXTENDED_KEY_USAGE (1 << 11) +#define EXT_CRL_DISTRIBUTION_POINTS (1 << 12) +#define EXT_INIHIBIT_ANYPOLICY (1 << 13) +#define EXT_FRESHEST_CRL (1 << 14) + +#define EXT_NS_CERT_TYPE (1 << 16) + +/* + * Storage format identifiers + * Recognized formats: PEM and DER + */ +#define X509_FORMAT_DER 1 +#define X509_FORMAT_PEM 2 + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures for parsing X.509 certificates and CRLs + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef asn1_buf x509_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef asn1_bitstring x509_bitstring; + +/** + * Container for ASN1 named information objects. + * It allows for Relative Distinguished Names (e.g. cn=polarssl,ou=code,etc.). + */ +typedef struct _x509_name +{ + x509_buf oid; /**< The object identifier. */ + x509_buf val; /**< The named value. */ + struct _x509_name *next; /**< The next named information object. */ +} +x509_name; + +/** + * Container for a sequence of ASN.1 items + */ +typedef asn1_sequence x509_sequence; + +/** Container for date and time (precision in seconds). */ +typedef struct _x509_time +{ + int year, mon, day; /**< Date. */ + int hour, min, sec; /**< Time. */ +} +x509_time; + +/** + * Container for an X.509 certificate. The certificate may be chained. + */ +typedef struct _x509_cert +{ + x509_buf raw; /**< The raw certificate data (DER). */ + x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; /**< The X.509 version. (0=v1, 1=v2, 2=v3) */ + x509_buf serial; /**< Unique id for certificate issued by a specific CA. */ + x509_buf sig_oid1; /**< Signature algorithm, e.g. sha1RSA */ + + x509_buf issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */ + x509_buf subject_raw; /**< The raw subject data (DER). Used for quick comparison. */ + + x509_name issuer; /**< The parsed issuer data (named information object). */ + x509_name subject; /**< The parsed subject data (named information object). */ + + x509_time valid_from; /**< Start time of certificate validity. */ + x509_time valid_to; /**< End time of certificate validity. */ + + x509_buf pk_oid; /**< Subject public key info. Includes the public key algorithm and the key itself. */ + rsa_context rsa; /**< Container for the RSA context. Only RSA is supported for public keys at this time. */ + + x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ + x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ + x509_buf v3_ext; /**< Optional X.509 v3 extensions. Only Basic Contraints are supported at this time. */ + x509_sequence subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName supported). */ + + int ext_types; /**< Bit string containing detected and parsed extensions */ + int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ + int max_pathlen; /**< Optional Basic Constraint extension value: The maximum path length to the root certificate. Path length is 1 higher than RFC 5280 'meaning', so 1+ */ + + unsigned char key_usage; /**< Optional key usage extension value: See the values below */ + + x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */ + + unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values below */ + + x509_buf sig_oid2; /**< Signature algorithm. Must match sig_oid1. */ + x509_buf sig; /**< Signature: hash of the tbs part signed with the private key. */ + int sig_alg; /**< Internal representation of the signature algorithm, e.g. SIG_RSA_MD2 */ + + struct _x509_cert *next; /**< Next certificate in the CA-chain. */ +} +x509_cert; + +/** + * Certificate revocation list entry. + * Contains the CA-specific serial numbers and revocation dates. + */ +typedef struct _x509_crl_entry +{ + x509_buf raw; + + x509_buf serial; + + x509_time revocation_date; + + x509_buf entry_ext; + + struct _x509_crl_entry *next; +} +x509_crl_entry; + +/** + * Certificate revocation list structure. + * Every CRL may have multiple entries. + */ +typedef struct _x509_crl +{ + x509_buf raw; /**< The raw certificate data (DER). */ + x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; + x509_buf sig_oid1; + + x509_buf issuer_raw; /**< The raw issuer data (DER). */ + + x509_name issuer; /**< The parsed issuer data (named information object). */ + + x509_time this_update; + x509_time next_update; + + x509_crl_entry entry; /**< The CRL entries containing the certificate revocation times for this CA. */ + + x509_buf crl_ext; + + x509_buf sig_oid2; + x509_buf sig; + int sig_alg; + + struct _x509_crl *next; +} +x509_crl; +/** \} name Structures for parsing X.509 certificates and CRLs */ +/** \} addtogroup x509_module */ + +/** + * \name Structures for writing X.509 certificates. + * XvP: commented out as they are not used. + * - typedef struct _x509_node x509_node; + * - typedef struct _x509_raw x509_raw; + */ +typedef struct _x509_node +{ + unsigned char *data; + unsigned char *p; + unsigned char *end; + + size_t len; +} +x509_node; + +typedef struct _x509_raw +{ + x509_node raw; + x509_node tbs; + + x509_node version; + x509_node serial; + x509_node tbs_signalg; + x509_node issuer; + x509_node validity; + x509_node subject; + x509_node subpubkey; + + x509_node signalg; + x509_node sign; +} +x509_raw; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Functions to read in DHM parameters, a certificate, CRL or private RSA key + * \{ + */ + +/** \ingroup x509_module */ +/** + * \brief Parse a single DER formatted certificate and add it + * to the chained list. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate DER data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_crt_der( x509_cert *chain, const unsigned char *buf, size_t buflen ); + +/** + * \brief Parse one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate data + * \param buflen size of the buffer + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen ); + +/** \ingroup x509_module */ +/** + * \brief Load one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path filename to read the certificates from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int x509parse_crtfile( x509_cert *chain, const char *path ); + +/** \ingroup x509_module */ +/** + * \brief Load one or more certificate files from a path and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path directory / folder to read the certificate files from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int x509parse_crtpath( x509_cert *chain, const char *path ); + +/** \ingroup x509_module */ +/** + * \brief Parse one or more CRLs and add them + * to the chained list + * + * \param chain points to the start of the chain + * \param buf buffer holding the CRL data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_crl( x509_crl *chain, const unsigned char *buf, size_t buflen ); + +/** \ingroup x509_module */ +/** + * \brief Load one or more CRLs and add them + * to the chained list + * + * \param chain points to the start of the chain + * \param path filename to read the CRLs from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_crlfile( x509_crl *chain, const char *path ); + +/** \ingroup x509_module */ +/** + * \brief Parse a private RSA key + * + * \param rsa RSA context to be initialized + * \param key input buffer + * \param keylen size of the buffer + * \param pwd password for decryption (optional) + * \param pwdlen size of the password + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_key( rsa_context *rsa, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ); + +/** \ingroup x509_module */ +/** + * \brief Load and parse a private RSA key + * + * \param rsa RSA context to be initialized + * \param path filename to read the private key from + * \param password password to decrypt the file (can be NULL) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_keyfile( rsa_context *rsa, const char *path, + const char *password ); + +/** \ingroup x509_module */ +/** + * \brief Parse a public RSA key + * + * \param rsa RSA context to be initialized + * \param key input buffer + * \param keylen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_public_key( rsa_context *rsa, + const unsigned char *key, size_t keylen ); + +/** \ingroup x509_module */ +/** + * \brief Load and parse a public RSA key + * + * \param rsa RSA context to be initialized + * \param path filename to read the private key from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_public_keyfile( rsa_context *rsa, const char *path ); + +/** \ingroup x509_module */ +/** + * \brief Parse DHM parameters + * + * \param dhm DHM context to be initialized + * \param dhmin input buffer + * \param dhminlen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_dhm( dhm_context *dhm, const unsigned char *dhmin, size_t dhminlen ); + +/** \ingroup x509_module */ +/** + * \brief Load and parse DHM parameters + * + * \param dhm DHM context to be initialized + * \param path filename to read the DHM Parameters from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_dhmfile( dhm_context *dhm, const char *path ); + +/** \} name Functions to read in DHM parameters, a certificate, CRL or private RSA key */ + +/** + * \brief Store the certificate DN in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param dn The X509 name to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_dn_gets( char *buf, size_t size, const x509_name *dn ); + +/** + * \brief Store the certificate serial in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param serial The X509 serial to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_serial_gets( char *buf, size_t size, const x509_buf *serial ); + +/** + * \brief Returns an informational string about the + * certificate. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crt The X509 certificate to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_cert_info( char *buf, size_t size, const char *prefix, + const x509_cert *crt ); + +/** + * \brief Returns an informational string about the + * CRL. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crl The X509 CRL to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_crl_info( char *buf, size_t size, const char *prefix, + const x509_crl *crl ); + +/** + * \brief Give an known OID, return its descriptive string. + * + * \param oid buffer containing the oid + * + * \return Return a string if the OID is known, + * or NULL otherwise. + */ +const char *x509_oid_get_description( x509_buf *oid ); + +/** + * \brief Give an OID, return a string version of its OID number. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param oid Buffer containing the OID + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509_oid_get_numeric_string( char *buf, size_t size, x509_buf *oid ); + +/** + * \brief Check a given x509_time against the system time and check + * if it is valid. + * + * \param time x509_time to check + * + * \return Return 0 if the x509_time is still valid, + * or 1 otherwise. + */ +int x509parse_time_expired( const x509_time *time ); + +/** + * \name Functions to verify a certificate + * \{ + */ +/** \ingroup x509_module */ +/** + * \brief Verify the certificate signature + * + * The verify callback is a user-supplied callback that + * can clear / modify / add flags for a certificate. If set, + * the verification callback is called for each + * certificate in the chain (from the trust-ca down to the + * presented crt). The parameters for the callback are: + * (void *parameter, x509_cert *crt, int certificate_depth, + * int *flags). With the flags representing current flags for + * that specific certificate and the certificate depth from + * the bottom (Peer cert depth = 0). + * + * All flags left after returning from the callback + * are also returned to the application. The function should + * return 0 for anything but a fatal error. + * + * \param crt a certificate to be verified + * \param trust_ca the trusted CA chain + * \param ca_crl the CRL chain for trusted CA's + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * + * \return 0 if successful or POLARSSL_ERR_X509_SIG_VERIFY_FAILED, + * in which case *flags will have one or more of + * the following values set: + * BADCERT_EXPIRED -- + * BADCERT_REVOKED -- + * BADCERT_CN_MISMATCH -- + * BADCERT_NOT_TRUSTED + * or another error in case of a fatal error encountered + * during the verification process. + */ +int x509parse_verify( x509_cert *crt, + x509_cert *trust_ca, + x509_crl *ca_crl, + const char *cn, int *flags, + int (*f_vrfy)(void *, x509_cert *, int, int *), + void *p_vrfy ); + +/** + * \brief Verify the certificate signature + * + * \param crt a certificate to be verified + * \param crl the CRL to verify against + * + * \return 1 if the certificate is revoked, 0 otherwise + * + */ +int x509parse_revoked( const x509_cert *crt, const x509_crl *crl ); + +/** \} name Functions to verify a certificate */ + + + +/** + * \name Functions to clear a certificate, CRL or private RSA key + * \{ + */ +/** \ingroup x509_module */ +/** + * \brief Unallocate all certificate data + * + * \param crt Certificate chain to free + */ +void x509_free( x509_cert *crt ); + +/** \ingroup x509_module */ +/** + * \brief Unallocate all CRL data + * + * \param crl CRL chain to free + */ +void x509_crl_free( x509_crl *crl ); + +/** \} name Functions to clear a certificate, CRL or private RSA key */ + + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int x509_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* x509.h */ diff --git a/src/libpolarssl/x509parse.c b/src/libpolarssl/x509parse.c new file mode 100644 index 0000000..b73dd1b --- /dev/null +++ b/src/libpolarssl/x509parse.c @@ -0,0 +1,3809 @@ +/* + * X.509 certificate and private key decoding + * + * Copyright (C) 2006-2011, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc3279.txt + * http://www.ietf.org/rfc/rfc3280.txt + * + * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#include "config.h" + +#if defined(POLARSSL_X509_PARSE_C) + +#include "x509.h" +#include "asn1.h" +#include "pem.h" +#include "des.h" +#if defined(POLARSSL_MD2_C) +#include "md2.h" +#endif +#if defined(POLARSSL_MD4_C) +#include "md4.h" +#endif +#if defined(POLARSSL_MD5_C) +#include "md5.h" +#endif +#if defined(POLARSSL_SHA1_C) +#include "sha1.h" +#endif +#if defined(POLARSSL_SHA2_C) +#include "sha2.h" +#endif +#if defined(POLARSSL_SHA4_C) +#include "sha4.h" +#endif +#include "dhm.h" +#if defined(POLARSSL_PKCS5_C) +#include "pkcs5.h" +#endif +#if defined(POLARSSL_PKCS12_C) +#include "pkcs12.h" +#endif + +#include +#include +#if defined(_WIN32) +#include +#else +#include +#endif + +#if defined(POLARSSL_FS_IO) +#include +#if !defined(_WIN32) +#include +#include +#include +#endif +#endif + +/* Compare a given OID string with an OID x509_buf * */ +#define OID_CMP(oid_str, oid_buf) \ + ( ( OID_SIZE(oid_str) == (oid_buf)->len ) && \ + memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) == 0) + +/* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ +static int x509_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + size_t len; + + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( ret ); + } + + end = *p + len; + + if( ( ret = asn1_get_int( p, end, ver ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_VERSION + ret ); + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_VERSION + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Version ::= INTEGER { v1(0), v2(1) } + */ +static int x509_crl_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + + if( ( ret = asn1_get_int( p, end, ver ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( POLARSSL_ERR_X509_CERT_INVALID_VERSION + ret ); + } + + return( 0 ); +} + +/* + * CertificateSerialNumber ::= INTEGER + */ +static int x509_get_serial( unsigned char **p, + const unsigned char *end, + x509_buf *serial ) +{ + int ret; + + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + if( **p != ( ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2 ) && + **p != ASN1_INTEGER ) + return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL + + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); + + serial->tag = *(*p)++; + + if( ( ret = asn1_get_len( p, end, &serial->len ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL + ret ); + + serial->p = *p; + *p += serial->len; + + return( 0 ); +} + +/* + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + */ +static int x509_get_alg( unsigned char **p, + const unsigned char *end, + x509_buf *alg ) +{ + int ret; + size_t len; + + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret ); + + end = *p + len; + alg->tag = **p; + + if( ( ret = asn1_get_tag( p, end, &alg->len, ASN1_OID ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret ); + + alg->p = *p; + *p += alg->len; + + if( *p == end ) + return( 0 ); + + /* + * assume the algorithm parameters must be NULL + */ + if( ( ret = asn1_get_tag( p, end, &len, ASN1_NULL ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret ); + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_ALG + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ +static int x509_get_attr_type_value( unsigned char **p, + const unsigned char *end, + x509_name *cur ) +{ + int ret; + size_t len; + x509_buf *oid; + x509_buf *val; + + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret ); + + oid = &cur->oid; + oid->tag = **p; + + if( ( ret = asn1_get_tag( p, end, &oid->len, ASN1_OID ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret ); + + oid->p = *p; + *p += oid->len; + + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + if( **p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING && + **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING && + **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); + + val = &cur->val; + val->tag = *(*p)++; + + if( ( ret = asn1_get_len( p, end, &val->len ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret ); + + val->p = *p; + *p += val->len; + + cur->next = NULL; + + return( 0 ); +} + +/* + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ +static int x509_get_name( unsigned char **p, + const unsigned char *end, + x509_name *cur ) +{ + int ret; + size_t len; + const unsigned char *end2; + x509_name *use; + + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SET ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret ); + + end2 = end; + end = *p + len; + use = cur; + + do + { + if( ( ret = x509_get_attr_type_value( p, end, use ) ) != 0 ) + return( ret ); + + if( *p != end ) + { + use->next = (x509_name *) malloc( + sizeof( x509_name ) ); + + if( use->next == NULL ) + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + + memset( use->next, 0, sizeof( x509_name ) ); + + use = use->next; + } + } + while( *p != end ); + + /* + * recurse until end of SEQUENCE is reached + */ + if( *p == end2 ) + return( 0 ); + + cur->next = (x509_name *) malloc( + sizeof( x509_name ) ); + + if( cur->next == NULL ) + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + + memset( cur->next, 0, sizeof( x509_name ) ); + + return( x509_get_name( p, end2, cur->next ) ); +} + +/* + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + */ +static int x509_get_time( unsigned char **p, + const unsigned char *end, + x509_time *time ) +{ + int ret; + size_t len; + char date[64]; + unsigned char tag; + + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + tag = **p; + + if ( tag == ASN1_UTC_TIME ) + { + (*p)++; + ret = asn1_get_len( p, end, &len ); + + if( ret != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret ); + + memset( date, 0, sizeof( date ) ); + memcpy( date, *p, ( len < sizeof( date ) - 1 ) ? + len : sizeof( date ) - 1 ); + + if( sscanf( date, "%2d%2d%2d%2d%2d%2d", + &time->year, &time->mon, &time->day, + &time->hour, &time->min, &time->sec ) < 5 ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE ); + + time->year += 100 * ( time->year < 50 ); + time->year += 1900; + + *p += len; + + return( 0 ); + } + else if ( tag == ASN1_GENERALIZED_TIME ) + { + (*p)++; + ret = asn1_get_len( p, end, &len ); + + if( ret != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret ); + + memset( date, 0, sizeof( date ) ); + memcpy( date, *p, ( len < sizeof( date ) - 1 ) ? + len : sizeof( date ) - 1 ); + + if( sscanf( date, "%4d%2d%2d%2d%2d%2d", + &time->year, &time->mon, &time->day, + &time->hour, &time->min, &time->sec ) < 5 ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE ); + + *p += len; + + return( 0 ); + } + else + return( POLARSSL_ERR_X509_CERT_INVALID_DATE + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); +} + + +/* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + */ +static int x509_get_dates( unsigned char **p, + const unsigned char *end, + x509_time *from, + x509_time *to ) +{ + int ret; + size_t len; + + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret ); + + end = *p + len; + + if( ( ret = x509_get_time( p, end, from ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_time( p, end, to ) ) != 0 ) + return( ret ); + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ +static int x509_get_pubkey( unsigned char **p, + const unsigned char *end, + x509_buf *pk_alg_oid, + mpi *N, mpi *E ) +{ + int ret; + size_t len; + unsigned char *end2; + + if( ( ret = x509_get_alg( p, end, pk_alg_oid ) ) != 0 ) + return( ret ); + + /* + * only RSA public keys handled at this time + */ + if( pk_alg_oid->len != 9 || + memcmp( pk_alg_oid->p, OID_PKCS1_RSA, 9 ) != 0 ) + { + return( POLARSSL_ERR_X509_UNKNOWN_PK_ALG ); + } + + if( ( ret = asn1_get_tag( p, end, &len, ASN1_BIT_STRING ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + ret ); + + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + end2 = *p + len; + + if( *(*p)++ != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY ); + + /* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ + if( ( ret = asn1_get_tag( p, end2, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + ret ); + + if( *p + len != end2 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = asn1_get_mpi( p, end2, N ) ) != 0 || + ( ret = asn1_get_mpi( p, end2, E ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + ret ); + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +static int x509_get_sig( unsigned char **p, + const unsigned char *end, + x509_buf *sig ) +{ + int ret; + size_t len; + + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + sig->tag = **p; + + if( ( ret = asn1_get_tag( p, end, &len, ASN1_BIT_STRING ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE + ret ); + + + if( --len < 1 || *(*p)++ != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE ); + + sig->len = len; + sig->p = *p; + + *p += len; + + return( 0 ); +} + +/* + * X.509 v2/v3 unique identifier (not parsed) + */ +static int x509_get_uid( unsigned char **p, + const unsigned char *end, + x509_buf *uid, int n ) +{ + int ret; + + if( *p == end ) + return( 0 ); + + uid->tag = **p; + + if( ( ret = asn1_get_tag( p, end, &uid->len, + ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + uid->p = *p; + *p += uid->len; + + return( 0 ); +} + +/* + * X.509 Extensions (No parsing of extensions, pointer should + * be either manually updated or extensions should be parsed! + */ +static int x509_get_ext( unsigned char **p, + const unsigned char *end, + x509_buf *ext, int tag ) +{ + int ret; + size_t len; + + if( *p == end ) + return( 0 ); + + ext->tag = **p; + + if( ( ret = asn1_get_tag( p, end, &ext->len, + ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | tag ) ) != 0 ) + return( ret ); + + ext->p = *p; + end = *p + ext->len; + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + if( end != *p + len ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL v2 extensions (no extensions parsed yet.) + */ +static int x509_get_crl_ext( unsigned char **p, + const unsigned char *end, + x509_buf *ext ) +{ + int ret; + size_t len = 0; + + /* Get explicit tag */ + if( ( ret = x509_get_ext( p, end, ext, 0) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + while( *p < end ) + { + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + *p += len; + } + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL v2 entry extensions (no extensions parsed yet.) + */ +static int x509_get_crl_entry_ext( unsigned char **p, + const unsigned char *end, + x509_buf *ext ) +{ + int ret; + size_t len = 0; + + /* OPTIONAL */ + if (end <= *p) + return( 0 ); + + ext->tag = **p; + ext->p = *p; + + /* + * Get CRL-entry extension sequence header + * crlEntryExtensions Extensions OPTIONAL -- if present, MUST be v2 + */ + if( ( ret = asn1_get_tag( p, end, &ext->len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + { + ext->p = NULL; + return( 0 ); + } + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + } + + end = *p + ext->len; + + if( end != *p + ext->len ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + *p += len; + } + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +static int x509_get_basic_constraints( unsigned char **p, + const unsigned char *end, + int *ca_istrue, + int *max_pathlen ) +{ + int ret; + size_t len; + + /* + * BasicConstraints ::= SEQUENCE { + * cA BOOLEAN DEFAULT FALSE, + * pathLenConstraint INTEGER (0..MAX) OPTIONAL } + */ + *ca_istrue = 0; /* DEFAULT FALSE */ + *max_pathlen = 0; /* endless */ + + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + if( *p == end ) + return 0; + + if( ( ret = asn1_get_bool( p, end, ca_istrue ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + ret = asn1_get_int( p, end, ca_istrue ); + + if( ret != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + if( *ca_istrue != 0 ) + *ca_istrue = 1; + } + + if( *p == end ) + return 0; + + if( ( ret = asn1_get_int( p, end, max_pathlen ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + (*max_pathlen)++; + + return 0; +} + +static int x509_get_ns_cert_type( unsigned char **p, + const unsigned char *end, + unsigned char *ns_cert_type) +{ + int ret; + x509_bitstring bs = { 0, 0, NULL }; + + if( ( ret = asn1_get_bitstring( p, end, &bs ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + if( bs.len != 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_INVALID_LENGTH ); + + /* Get actual bitstring */ + *ns_cert_type = *bs.p; + return 0; +} + +static int x509_get_key_usage( unsigned char **p, + const unsigned char *end, + unsigned char *key_usage) +{ + int ret; + x509_bitstring bs = { 0, 0, NULL }; + + if( ( ret = asn1_get_bitstring( p, end, &bs ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + if( bs.len < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_INVALID_LENGTH ); + + /* Get actual bitstring */ + *key_usage = *bs.p; + return 0; +} + +/* + * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + * + * KeyPurposeId ::= OBJECT IDENTIFIER + */ +static int x509_get_ext_key_usage( unsigned char **p, + const unsigned char *end, + x509_sequence *ext_key_usage) +{ + int ret; + + if( ( ret = asn1_get_sequence_of( p, end, ext_key_usage, ASN1_OID ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + /* Sequence length must be >= 1 */ + if( ext_key_usage->buf.p == NULL ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_INVALID_LENGTH ); + + return 0; +} + +/* + * SubjectAltName ::= GeneralNames + * + * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + * + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER } + * + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * + * EDIPartyName ::= SEQUENCE { + * nameAssigner [0] DirectoryString OPTIONAL, + * partyName [1] DirectoryString } + * + * NOTE: PolarSSL only parses and uses dNSName at this point. + */ +static int x509_get_subject_alt_name( unsigned char **p, + const unsigned char *end, + x509_sequence *subject_alt_name ) +{ + int ret; + size_t len, tag_len; + asn1_buf *buf; + unsigned char tag; + asn1_sequence *cur = subject_alt_name; + + /* Get main sequence tag */ + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + if( *p + len != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + tag = **p; + (*p)++; + if( ( ret = asn1_get_len( p, end, &tag_len ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + if( ( tag & ASN1_CONTEXT_SPECIFIC ) != ASN1_CONTEXT_SPECIFIC ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); + + if( tag != ( ASN1_CONTEXT_SPECIFIC | 2 ) ) + { + *p += tag_len; + continue; + } + + buf = &(cur->buf); + buf->tag = tag; + buf->p = *p; + buf->len = tag_len; + *p += buf->len; + + /* Allocate and assign next pointer */ + if (*p < end) + { + cur->next = (asn1_sequence *) malloc( + sizeof( asn1_sequence ) ); + + if( cur->next == NULL ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_MALLOC_FAILED ); + + memset( cur->next, 0, sizeof( asn1_sequence ) ); + cur = cur->next; + } + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 v3 extensions + * + * TODO: Perform all of the basic constraints tests required by the RFC + * TODO: Set values for undetected extensions to a sane default? + * + */ +static int x509_get_crt_ext( unsigned char **p, + const unsigned char *end, + x509_cert *crt ) +{ + int ret; + size_t len; + unsigned char *end_ext_data, *end_ext_octet; + + if( ( ret = x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + while( *p < end ) + { + /* + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + x509_buf extn_oid = {0, 0, NULL}; + int is_critical = 0; /* DEFAULT FALSE */ + + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + end_ext_data = *p + len; + + /* Get extension ID */ + extn_oid.tag = **p; + + if( ( ret = asn1_get_tag( p, end, &extn_oid.len, ASN1_OID ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + extn_oid.p = *p; + *p += extn_oid.len; + + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + /* Get optional critical */ + if( ( ret = asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 && + ( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + /* Data should be octet string type */ + if( ( ret = asn1_get_tag( p, end_ext_data, &len, + ASN1_OCTET_STRING ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + end_ext_octet = *p + len; + + if( end_ext_octet != end_ext_data ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * Detect supported extensions + */ + if( ( OID_SIZE( OID_BASIC_CONSTRAINTS ) == extn_oid.len ) && + memcmp( extn_oid.p, OID_BASIC_CONSTRAINTS, extn_oid.len ) == 0 ) + { + /* Parse basic constraints */ + if( ( ret = x509_get_basic_constraints( p, end_ext_octet, + &crt->ca_istrue, &crt->max_pathlen ) ) != 0 ) + return ( ret ); + crt->ext_types |= EXT_BASIC_CONSTRAINTS; + } + else if( ( OID_SIZE( OID_NS_CERT_TYPE ) == extn_oid.len ) && + memcmp( extn_oid.p, OID_NS_CERT_TYPE, extn_oid.len ) == 0 ) + { + /* Parse netscape certificate type */ + if( ( ret = x509_get_ns_cert_type( p, end_ext_octet, + &crt->ns_cert_type ) ) != 0 ) + return ( ret ); + crt->ext_types |= EXT_NS_CERT_TYPE; + } + else if( ( OID_SIZE( OID_KEY_USAGE ) == extn_oid.len ) && + memcmp( extn_oid.p, OID_KEY_USAGE, extn_oid.len ) == 0 ) + { + /* Parse key usage */ + if( ( ret = x509_get_key_usage( p, end_ext_octet, + &crt->key_usage ) ) != 0 ) + return ( ret ); + crt->ext_types |= EXT_KEY_USAGE; + } + else if( ( OID_SIZE( OID_EXTENDED_KEY_USAGE ) == extn_oid.len ) && + memcmp( extn_oid.p, OID_EXTENDED_KEY_USAGE, extn_oid.len ) == 0 ) + { + /* Parse extended key usage */ + if( ( ret = x509_get_ext_key_usage( p, end_ext_octet, + &crt->ext_key_usage ) ) != 0 ) + return ( ret ); + crt->ext_types |= EXT_EXTENDED_KEY_USAGE; + } + else if( ( OID_SIZE( OID_SUBJECT_ALT_NAME ) == extn_oid.len ) && + memcmp( extn_oid.p, OID_SUBJECT_ALT_NAME, extn_oid.len ) == 0 ) + { + /* Parse extended key usage */ + if( ( ret = x509_get_subject_alt_name( p, end_ext_octet, + &crt->subject_alt_names ) ) != 0 ) + return ( ret ); + crt->ext_types |= EXT_SUBJECT_ALT_NAME; + } + else + { + /* No parser found, skip extension */ + *p = end_ext_octet; + +#if !defined(POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) + if( is_critical ) + { + /* Data is marked as critical: fail */ + return ( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); + } +#endif + } + } + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL Entries + */ +static int x509_get_entries( unsigned char **p, + const unsigned char *end, + x509_crl_entry *entry ) +{ + int ret; + size_t entry_len; + x509_crl_entry *cur_entry = entry; + + if( *p == end ) + return( 0 ); + + if( ( ret = asn1_get_tag( p, end, &entry_len, + ASN1_SEQUENCE | ASN1_CONSTRUCTED ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + end = *p + entry_len; + + while( *p < end ) + { + size_t len2; + const unsigned char *end2; + + if( ( ret = asn1_get_tag( p, end, &len2, + ASN1_SEQUENCE | ASN1_CONSTRUCTED ) ) != 0 ) + { + return( ret ); + } + + cur_entry->raw.tag = **p; + cur_entry->raw.p = *p; + cur_entry->raw.len = len2; + end2 = *p + len2; + + if( ( ret = x509_get_serial( p, end2, &cur_entry->serial ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_time( p, end2, &cur_entry->revocation_date ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_crl_entry_ext( p, end2, &cur_entry->entry_ext ) ) != 0 ) + return( ret ); + + if ( *p < end ) + { + cur_entry->next = malloc( sizeof( x509_crl_entry ) ); + + if( cur_entry->next == NULL ) + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + + cur_entry = cur_entry->next; + memset( cur_entry, 0, sizeof( x509_crl_entry ) ); + } + } + + return( 0 ); +} + +static int x509_get_sig_alg( const x509_buf *sig_oid, int *sig_alg ) +{ + if( sig_oid->len == 9 && + memcmp( sig_oid->p, OID_PKCS1, 8 ) == 0 ) + { + if( sig_oid->p[8] >= 2 && sig_oid->p[8] <= 5 ) + { + *sig_alg = sig_oid->p[8]; + return( 0 ); + } + + if ( sig_oid->p[8] >= 11 && sig_oid->p[8] <= 14 ) + { + *sig_alg = sig_oid->p[8]; + return( 0 ); + } + + return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG ); + } + if( sig_oid->len == 5 && + memcmp( sig_oid->p, OID_RSA_SHA_OBS, 5 ) == 0 ) + { + *sig_alg = SIG_RSA_SHA1; + return( 0 ); + } + + return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG ); +} + +/* + * Parse and fill a single X.509 certificate in DER format + */ +int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, + size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p, *end, *crt_end; + + /* + * Check for valid input + */ + if( crt == NULL || buf == NULL ) + return( POLARSSL_ERR_X509_INVALID_INPUT ); + + p = (unsigned char *) malloc( len = buflen ); + + if( p == NULL ) + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + + memcpy( p, buf, buflen ); + + buflen = 0; + + crt->raw.p = p; + crt->raw.len = len; + end = p + len; + + /* + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_free( crt ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT ); + } + + if( len > (size_t) ( end - p ) ) + { + x509_free( crt ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + crt_end = p + len; + + /* + * TBSCertificate ::= SEQUENCE { + */ + crt->tbs.p = p; + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_free( crt ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + end = p + len; + crt->tbs.len = end - crt->tbs.p; + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + * + * CertificateSerialNumber ::= INTEGER + * + * signature AlgorithmIdentifier + */ + if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 || + ( ret = x509_get_serial( &p, end, &crt->serial ) ) != 0 || + ( ret = x509_get_alg( &p, end, &crt->sig_oid1 ) ) != 0 ) + { + x509_free( crt ); + return( ret ); + } + + crt->version++; + + if( crt->version > 3 ) + { + x509_free( crt ); + return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION ); + } + + if( ( ret = x509_get_sig_alg( &crt->sig_oid1, &crt->sig_alg ) ) != 0 ) + { + x509_free( crt ); + return( ret ); + } + + /* + * issuer Name + */ + crt->issuer_raw.p = p; + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_free( crt ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + if( ( ret = x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) + { + x509_free( crt ); + return( ret ); + } + + crt->issuer_raw.len = p - crt->issuer_raw.p; + + /* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + * + */ + if( ( ret = x509_get_dates( &p, end, &crt->valid_from, + &crt->valid_to ) ) != 0 ) + { + x509_free( crt ); + return( ret ); + } + + /* + * subject Name + */ + crt->subject_raw.p = p; + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_free( crt ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + if( len && ( ret = x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) + { + x509_free( crt ); + return( ret ); + } + + crt->subject_raw.len = p - crt->subject_raw.p; + + /* + * SubjectPublicKeyInfo ::= SEQUENCE + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_free( crt ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + if( ( ret = x509_get_pubkey( &p, p + len, &crt->pk_oid, + &crt->rsa.N, &crt->rsa.E ) ) != 0 ) + { + x509_free( crt ); + return( ret ); + } + + if( ( ret = rsa_check_pubkey( &crt->rsa ) ) != 0 ) + { + x509_free( crt ); + return( ret ); + } + + crt->rsa.len = mpi_size( &crt->rsa.N ); + + /* + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * extensions [3] EXPLICIT Extensions OPTIONAL + * -- If present, version shall be v3 + */ + if( crt->version == 2 || crt->version == 3 ) + { + ret = x509_get_uid( &p, end, &crt->issuer_id, 1 ); + if( ret != 0 ) + { + x509_free( crt ); + return( ret ); + } + } + + if( crt->version == 2 || crt->version == 3 ) + { + ret = x509_get_uid( &p, end, &crt->subject_id, 2 ); + if( ret != 0 ) + { + x509_free( crt ); + return( ret ); + } + } + + if( crt->version == 3 ) + { + ret = x509_get_crt_ext( &p, end, crt); + if( ret != 0 ) + { + x509_free( crt ); + return( ret ); + } + } + + if( p != end ) + { + x509_free( crt ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + end = crt_end; + + /* + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + */ + if( ( ret = x509_get_alg( &p, end, &crt->sig_oid2 ) ) != 0 ) + { + x509_free( crt ); + return( ret ); + } + + if( crt->sig_oid1.len != crt->sig_oid2.len || + memcmp( crt->sig_oid1.p, crt->sig_oid2.p, crt->sig_oid1.len ) != 0 ) + { + x509_free( crt ); + return( POLARSSL_ERR_X509_CERT_SIG_MISMATCH ); + } + + if( ( ret = x509_get_sig( &p, end, &crt->sig ) ) != 0 ) + { + x509_free( crt ); + return( ret ); + } + + if( p != end ) + { + x509_free( crt ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +/* + * Parse one X.509 certificate in DER format from a buffer and add them to a + * chained list + */ +int x509parse_crt_der( x509_cert *chain, const unsigned char *buf, size_t buflen ) +{ + int ret; + x509_cert *crt = chain, *prev = NULL; + + /* + * Check for valid input + */ + if( crt == NULL || buf == NULL ) + return( POLARSSL_ERR_X509_INVALID_INPUT ); + + while( crt->version != 0 && crt->next != NULL ) + { + prev = crt; + crt = crt->next; + } + + /* + * Add new certificate on the end of the chain if needed. + */ + if ( crt->version != 0 && crt->next == NULL) + { + crt->next = (x509_cert *) malloc( sizeof( x509_cert ) ); + + if( crt->next == NULL ) + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + + prev = crt; + crt = crt->next; + memset( crt, 0, sizeof( x509_cert ) ); + } + + if( ( ret = x509parse_crt_der_core( crt, buf, buflen ) ) != 0 ) + { + if( prev ) + prev->next = NULL; + + if( crt != chain ) + free( crt ); + + return( ret ); + } + + return( 0 ); +} + +/* + * Parse one or more PEM certificates from a buffer and add them to the chained list + */ +int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen ) +{ + int ret, success = 0, first_error = 0, total_failed = 0; + int buf_format = X509_FORMAT_DER; + + /* + * Check for valid input + */ + if( chain == NULL || buf == NULL ) + return( POLARSSL_ERR_X509_INVALID_INPUT ); + + /* + * Determine buffer content. Buffer contains either one DER certificate or + * one or more PEM certificates. + */ +#if defined(POLARSSL_PEM_C) + if( strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL ) + buf_format = X509_FORMAT_PEM; +#endif + + if( buf_format == X509_FORMAT_DER ) + return x509parse_crt_der( chain, buf, buflen ); + +#if defined(POLARSSL_PEM_C) + if( buf_format == X509_FORMAT_PEM ) + { + pem_context pem; + + while( buflen > 0 ) + { + size_t use_len; + pem_init( &pem ); + + ret = pem_read_buffer( &pem, + "-----BEGIN CERTIFICATE-----", + "-----END CERTIFICATE-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + buflen -= use_len; + buf += use_len; + } + else if( ret == POLARSSL_ERR_PEM_BAD_INPUT_DATA ) + { + return( ret ); + } + else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + pem_free( &pem ); + + /* + * PEM header and footer were found + */ + buflen -= use_len; + buf += use_len; + + if( first_error == 0 ) + first_error = ret; + + continue; + } + else + break; + + ret = x509parse_crt_der( chain, pem.buf, pem.buflen ); + + pem_free( &pem ); + + if( ret != 0 ) + { + /* + * Quit parsing on a memory error + */ + if( ret == POLARSSL_ERR_X509_MALLOC_FAILED ) + return( ret ); + + if( first_error == 0 ) + first_error = ret; + + total_failed++; + continue; + } + + success = 1; + } + } +#endif + + if( success ) + return( total_failed ); + else if( first_error ) + return( first_error ); + else + return( POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT ); +} + +/* + * Parse one or more CRLs and add them to the chained list + */ +int x509parse_crl( x509_crl *chain, const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + x509_crl *crl; +#if defined(POLARSSL_PEM_C) + size_t use_len; + pem_context pem; +#endif + + crl = chain; + + /* + * Check for valid input + */ + if( crl == NULL || buf == NULL ) + return( POLARSSL_ERR_X509_INVALID_INPUT ); + + while( crl->version != 0 && crl->next != NULL ) + crl = crl->next; + + /* + * Add new CRL on the end of the chain if needed. + */ + if ( crl->version != 0 && crl->next == NULL) + { + crl->next = (x509_crl *) malloc( sizeof( x509_crl ) ); + + if( crl->next == NULL ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + } + + crl = crl->next; + memset( crl, 0, sizeof( x509_crl ) ); + } + +#if defined(POLARSSL_PEM_C) + pem_init( &pem ); + ret = pem_read_buffer( &pem, + "-----BEGIN X509 CRL-----", + "-----END X509 CRL-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + buflen -= use_len; + buf += use_len; + + /* + * Steal PEM buffer + */ + p = pem.buf; + pem.buf = NULL; + len = pem.buflen; + pem_free( &pem ); + } + else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + pem_free( &pem ); + return( ret ); + } + else + { + /* + * nope, copy the raw DER data + */ + p = (unsigned char *) malloc( len = buflen ); + + if( p == NULL ) + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + + memcpy( p, buf, buflen ); + + buflen = 0; + } +#else + p = (unsigned char *) malloc( len = buflen ); + + if( p == NULL ) + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + + memcpy( p, buf, buflen ); + + buflen = 0; +#endif + + crl->raw.p = p; + crl->raw.len = len; + end = p + len; + + /* + * CertificateList ::= SEQUENCE { + * tbsCertList TBSCertList, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT ); + } + + if( len != (size_t) ( end - p ) ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* + * TBSCertList ::= SEQUENCE { + */ + crl->tbs.p = p; + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + end = p + len; + crl->tbs.len = end - crl->tbs.p; + + /* + * Version ::= INTEGER OPTIONAL { v1(0), v2(1) } + * -- if present, MUST be v2 + * + * signature AlgorithmIdentifier + */ + if( ( ret = x509_crl_get_version( &p, end, &crl->version ) ) != 0 || + ( ret = x509_get_alg( &p, end, &crl->sig_oid1 ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + crl->version++; + + if( crl->version > 2 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION ); + } + + if( ( ret = x509_get_sig_alg( &crl->sig_oid1, &crl->sig_alg ) ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG ); + } + + /* + * issuer Name + */ + crl->issuer_raw.p = p; + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + if( ( ret = x509_get_name( &p, p + len, &crl->issuer ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + crl->issuer_raw.len = p - crl->issuer_raw.p; + + /* + * thisUpdate Time + * nextUpdate Time OPTIONAL + */ + if( ( ret = x509_get_time( &p, end, &crl->this_update ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + if( ( ret = x509_get_time( &p, end, &crl->next_update ) ) != 0 ) + { + if ( ret != ( POLARSSL_ERR_X509_CERT_INVALID_DATE + + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) && + ret != ( POLARSSL_ERR_X509_CERT_INVALID_DATE + + POLARSSL_ERR_ASN1_OUT_OF_DATA ) ) + { + x509_crl_free( crl ); + return( ret ); + } + } + + /* + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, MUST be v2 + * } OPTIONAL + */ + if( ( ret = x509_get_entries( &p, end, &crl->entry ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + /* + * crlExtensions EXPLICIT Extensions OPTIONAL + * -- if present, MUST be v2 + */ + if( crl->version == 2 ) + { + ret = x509_get_crl_ext( &p, end, &crl->crl_ext ); + + if( ret != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + } + + if( p != end ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + end = crl->raw.p + crl->raw.len; + + /* + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + */ + if( ( ret = x509_get_alg( &p, end, &crl->sig_oid2 ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + if( crl->sig_oid1.len != crl->sig_oid2.len || + memcmp( crl->sig_oid1.p, crl->sig_oid2.p, crl->sig_oid1.len ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_SIG_MISMATCH ); + } + + if( ( ret = x509_get_sig( &p, end, &crl->sig ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + if( p != end ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + if( buflen > 0 ) + { + crl->next = (x509_crl *) malloc( sizeof( x509_crl ) ); + + if( crl->next == NULL ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + } + + crl = crl->next; + memset( crl, 0, sizeof( x509_crl ) ); + + return( x509parse_crl( crl, buf, buflen ) ); + } + + return( 0 ); +} + +#if defined(POLARSSL_FS_IO) +/* + * Load all data from a file into a given buffer. + */ +int load_file( const char *path, unsigned char **buf, size_t *n ) +{ + FILE *f; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_X509_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + *n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( ( *buf = (unsigned char *) malloc( *n + 1 ) ) == NULL ) + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + free( *buf ); + return( POLARSSL_ERR_X509_FILE_IO_ERROR ); + } + + fclose( f ); + + (*buf)[*n] = '\0'; + + return( 0 ); +} + +/* + * Load one or more certificates and add them to the chained list + */ +int x509parse_crtfile( x509_cert *chain, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if ( (ret = load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = x509parse_crt( chain, buf, n ); + + memset( buf, 0, n + 1 ); + free( buf ); + + return( ret ); +} + +int x509parse_crtpath( x509_cert *chain, const char *path ) +{ + int ret = 0; +#if defined(_WIN32) + int w_ret; + WCHAR szDir[MAX_PATH]; + char filename[MAX_PATH]; + char *p; + int len = strlen( path ); + + WIN32_FIND_DATAW file_data; + HANDLE hFind; + + if( len > MAX_PATH - 3 ) + return( POLARSSL_ERR_X509_INVALID_INPUT ); + + memset( szDir, 0, sizeof(szDir) ); + memset( filename, 0, MAX_PATH ); + memcpy( filename, path, len ); + filename[len++] = '\\'; + p = filename + len; + filename[len++] = '*'; + + w_ret = MultiByteToWideChar( CP_ACP, 0, path, len, szDir, MAX_PATH - 3 ); + + hFind = FindFirstFileW( szDir, &file_data ); + if (hFind == INVALID_HANDLE_VALUE) + return( POLARSSL_ERR_X509_FILE_IO_ERROR ); + + len = MAX_PATH - len; + do + { + memset( p, 0, len ); + + if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + continue; + + w_ret = WideCharToMultiByte( CP_ACP, 0, file_data.cFileName, + lstrlenW(file_data.cFileName), + p, len - 1, + NULL, NULL ); + + w_ret = x509parse_crtfile( chain, filename ); + if( w_ret < 0 ) + ret++; + else + ret += w_ret; + } + while( FindNextFileW( hFind, &file_data ) != 0 ); + + if (GetLastError() != ERROR_NO_MORE_FILES) + ret = POLARSSL_ERR_X509_FILE_IO_ERROR; + +cleanup: + FindClose( hFind ); +#else + int t_ret, i; + struct stat sb; + struct dirent entry, *result = NULL; + char entry_name[255]; + DIR *dir = opendir( path ); + + if( dir == NULL) + return( POLARSSL_ERR_X509_FILE_IO_ERROR ); + + while( ( t_ret = readdir_r( dir, &entry, &result ) ) == 0 ) + { + if( result == NULL ) + break; + + snprintf( entry_name, sizeof(entry_name), "%s/%s", path, entry.d_name ); + + i = stat( entry_name, &sb ); + + if( i == -1 ) + return( POLARSSL_ERR_X509_FILE_IO_ERROR ); + + if( !S_ISREG( sb.st_mode ) ) + continue; + + // Ignore parse errors + // + t_ret = x509parse_crtfile( chain, entry_name ); + if( t_ret < 0 ) + ret++; + else + ret += t_ret; + } + closedir( dir ); +#endif + + return( ret ); +} + +/* + * Load one or more CRLs and add them to the chained list + */ +int x509parse_crlfile( x509_crl *chain, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if ( (ret = load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = x509parse_crl( chain, buf, n ); + + memset( buf, 0, n + 1 ); + free( buf ); + + return( ret ); +} + +/* + * Load and parse a private RSA key + */ +int x509parse_keyfile( rsa_context *rsa, const char *path, const char *pwd ) +{ + int ret; + size_t n; + unsigned char *buf; + + if ( (ret = load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + if( pwd == NULL ) + ret = x509parse_key( rsa, buf, n, NULL, 0 ); + else + ret = x509parse_key( rsa, buf, n, + (unsigned char *) pwd, strlen( pwd ) ); + + memset( buf, 0, n + 1 ); + free( buf ); + + return( ret ); +} + +/* + * Load and parse a public RSA key + */ +int x509parse_public_keyfile( rsa_context *rsa, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if ( (ret = load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = x509parse_public_key( rsa, buf, n ); + + memset( buf, 0, n + 1 ); + free( buf ); + + return( ret ); +} +#endif /* POLARSSL_FS_IO */ + +/* + * Parse a PKCS#1 encoded private RSA key + */ +static int x509parse_key_pkcs1_der( rsa_context *rsa, + const unsigned char *key, + size_t keylen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + + p = (unsigned char *) key; + end = p + keylen; + + /* + * This function parses the RSAPrivateKey (PKCS#1) + * + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = asn1_get_int( &p, end, &rsa->ver ) ) != 0 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + if( rsa->ver != 0 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_VERSION + ret ); + } + + if( ( ret = asn1_get_mpi( &p, end, &rsa->N ) ) != 0 || + ( ret = asn1_get_mpi( &p, end, &rsa->E ) ) != 0 || + ( ret = asn1_get_mpi( &p, end, &rsa->D ) ) != 0 || + ( ret = asn1_get_mpi( &p, end, &rsa->P ) ) != 0 || + ( ret = asn1_get_mpi( &p, end, &rsa->Q ) ) != 0 || + ( ret = asn1_get_mpi( &p, end, &rsa->DP ) ) != 0 || + ( ret = asn1_get_mpi( &p, end, &rsa->DQ ) ) != 0 || + ( ret = asn1_get_mpi( &p, end, &rsa->QP ) ) != 0 ) + { + rsa_free( rsa ); + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + rsa->len = mpi_size( &rsa->N ); + + if( p != end ) + { + rsa_free( rsa ); + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + if( ( ret = rsa_check_privkey( rsa ) ) != 0 ) + { + rsa_free( rsa ); + return( ret ); + } + + return( 0 ); +} + +/* + * Parse an unencrypted PKCS#8 encoded private RSA key + */ +static int x509parse_key_pkcs8_unencrypted_der( + rsa_context *rsa, + const unsigned char *key, + size_t keylen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + x509_buf pk_alg_oid; + + p = (unsigned char *) key; + end = p + keylen; + + /* + * This function parses the PrivatKeyInfo object (PKCS#8) + * + * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * algorithm AlgorithmIdentifier, + * PrivateKey BIT STRING + * } + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * The PrivateKey BIT STRING is a PKCS#1 RSAPrivateKey + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = asn1_get_int( &p, end, &rsa->ver ) ) != 0 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + if( rsa->ver != 0 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_VERSION + ret ); + } + + if( ( ret = x509_get_alg( &p, end, &pk_alg_oid ) ) != 0 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + /* + * only RSA keys handled at this time + */ + if( pk_alg_oid.len != 9 || + memcmp( pk_alg_oid.p, OID_PKCS1_RSA, 9 ) != 0 ) + { + return( POLARSSL_ERR_X509_UNKNOWN_PK_ALG ); + } + + /* + * Get the OCTET STRING and parse the PKCS#1 format inside + */ + if( ( ret = asn1_get_tag( &p, end, &len, ASN1_OCTET_STRING ) ) != 0 ) + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + + if( ( end - p ) < 1 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + } + + end = p + len; + + if( ( ret = x509parse_key_pkcs1_der( rsa, p, end - p ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Parse an encrypted PKCS#8 encoded private RSA key + */ +static int x509parse_key_pkcs8_encrypted_der( + rsa_context *rsa, + const unsigned char *key, + size_t keylen, + const unsigned char *pwd, + size_t pwdlen ) +{ + int ret; + size_t len; + unsigned char *p, *end, *end2; + x509_buf pbe_alg_oid, pbe_params; + unsigned char buf[2048]; + + memset(buf, 0, 2048); + + p = (unsigned char *) key; + end = p + keylen; + + if( pwdlen == 0 ) + return( POLARSSL_ERR_X509_PASSWORD_REQUIRED ); + + /* + * This function parses the EncryptedPrivatKeyInfo object (PKCS#8) + * + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm EncryptionAlgorithmIdentifier, + * encryptedData EncryptedData + * } + * + * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * EncryptedData ::= OCTET STRING + * + * The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + end2 = p + len; + + if( ( ret = asn1_get_tag( &p, end, &pbe_alg_oid.len, ASN1_OID ) ) != 0 ) + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + + pbe_alg_oid.p = p; + p += pbe_alg_oid.len; + + /* + * Store the algorithm parameters + */ + pbe_params.p = p; + pbe_params.len = end2 - p; + p += pbe_params.len; + + if( ( ret = asn1_get_tag( &p, end, &len, ASN1_OCTET_STRING ) ) != 0 ) + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + + // buf has been sized to 2048 bytes + if( len > 2048 ) + return( POLARSSL_ERR_X509_INVALID_INPUT ); + + /* + * Decrypt EncryptedData with appropriate PDE + */ +#if defined(POLARSSL_PKCS12_C) + if( OID_CMP( OID_PKCS12_PBE_SHA1_DES3_EDE_CBC, &pbe_alg_oid ) ) + { + if( ( ret = pkcs12_pbe( &pbe_params, PKCS12_PBE_DECRYPT, + POLARSSL_CIPHER_DES_EDE3_CBC, POLARSSL_MD_SHA1, + pwd, pwdlen, p, len, buf ) ) != 0 ) + { + if( ret == POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH ) + return( POLARSSL_ERR_X509_PASSWORD_MISMATCH ); + + return( ret ); + } + } + else if( OID_CMP( OID_PKCS12_PBE_SHA1_DES2_EDE_CBC, &pbe_alg_oid ) ) + { + if( ( ret = pkcs12_pbe( &pbe_params, PKCS12_PBE_DECRYPT, + POLARSSL_CIPHER_DES_EDE_CBC, POLARSSL_MD_SHA1, + pwd, pwdlen, p, len, buf ) ) != 0 ) + { + if( ret == POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH ) + return( POLARSSL_ERR_X509_PASSWORD_MISMATCH ); + + return( ret ); + } + } + else if( OID_CMP( OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) ) + { + if( ( ret = pkcs12_pbe_sha1_rc4_128( &pbe_params, + PKCS12_PBE_DECRYPT, + pwd, pwdlen, + p, len, buf ) ) != 0 ) + { + return( ret ); + } + + // Best guess for password mismatch when using RC4. If first tag is + // not ASN1_CONSTRUCTED | ASN1_SEQUENCE + // + if( *buf != ( ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) + return( POLARSSL_ERR_X509_PASSWORD_MISMATCH ); + } + else +#endif /* POLARSSL_PKCS12_C */ +#if defined(POLARSSL_PKCS5_C) + if( OID_CMP( OID_PKCS5_PBES2, &pbe_alg_oid ) ) + { + if( ( ret = pkcs5_pbes2( &pbe_params, PKCS5_DECRYPT, pwd, pwdlen, + p, len, buf ) ) != 0 ) + { + if( ret == POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH ) + return( POLARSSL_ERR_X509_PASSWORD_MISMATCH ); + + return( ret ); + } + } + else +#endif /* POLARSSL_PKCS5_C */ + return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE ); + + return x509parse_key_pkcs8_unencrypted_der( rsa, buf, len ); +} + +/* + * Parse a private RSA key + */ +int x509parse_key( rsa_context *rsa, const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ) +{ + int ret; + +#if defined(POLARSSL_PEM_C) + size_t len; + pem_context pem; + + pem_init( &pem ); + ret = pem_read_buffer( &pem, + "-----BEGIN RSA PRIVATE KEY-----", + "-----END RSA PRIVATE KEY-----", + key, pwd, pwdlen, &len ); + if( ret == 0 ) + { + if( ( ret = x509parse_key_pkcs1_der( rsa, pem.buf, pem.buflen ) ) != 0 ) + { + rsa_free( rsa ); + } + + pem_free( &pem ); + return( ret ); + } + else if( ret == POLARSSL_ERR_PEM_PASSWORD_MISMATCH ) + return( POLARSSL_ERR_X509_PASSWORD_MISMATCH ); + else if( ret == POLARSSL_ERR_PEM_PASSWORD_REQUIRED ) + return( POLARSSL_ERR_X509_PASSWORD_REQUIRED ); + else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); + + ret = pem_read_buffer( &pem, + "-----BEGIN PRIVATE KEY-----", + "-----END PRIVATE KEY-----", + key, NULL, 0, &len ); + if( ret == 0 ) + { + if( ( ret = x509parse_key_pkcs8_unencrypted_der( rsa, + pem.buf, pem.buflen ) ) != 0 ) + { + rsa_free( rsa ); + } + + pem_free( &pem ); + return( ret ); + } + else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); + + ret = pem_read_buffer( &pem, + "-----BEGIN ENCRYPTED PRIVATE KEY-----", + "-----END ENCRYPTED PRIVATE KEY-----", + key, NULL, 0, &len ); + if( ret == 0 ) + { + if( ( ret = x509parse_key_pkcs8_encrypted_der( rsa, + pem.buf, pem.buflen, + pwd, pwdlen ) ) != 0 ) + { + rsa_free( rsa ); + } + + pem_free( &pem ); + return( ret ); + } + else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#else + ((void) pwd); + ((void) pwdlen); +#endif /* POLARSSL_PEM_C */ + + // At this point we only know it's not a PEM formatted key. Could be any + // of the known DER encoded private key formats + // + // We try the different DER format parsers to see if one passes without + // error + // + if( ( ret = x509parse_key_pkcs8_encrypted_der( rsa, key, keylen, + pwd, pwdlen ) ) == 0 ) + { + return( 0 ); + } + + rsa_free( rsa ); + + if( ret == POLARSSL_ERR_X509_PASSWORD_MISMATCH ) + { + return( ret ); + } + + if( ( ret = x509parse_key_pkcs8_unencrypted_der( rsa, key, keylen ) ) == 0 ) + return( 0 ); + + rsa_free( rsa ); + + if( ( ret = x509parse_key_pkcs1_der( rsa, key, keylen ) ) == 0 ) + return( 0 ); + + rsa_free( rsa ); + + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT ); +} + +/* + * Parse a public RSA key + */ +int x509parse_public_key( rsa_context *rsa, const unsigned char *key, size_t keylen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + x509_buf alg_oid; +#if defined(POLARSSL_PEM_C) + pem_context pem; + + pem_init( &pem ); + ret = pem_read_buffer( &pem, + "-----BEGIN PUBLIC KEY-----", + "-----END PUBLIC KEY-----", + key, NULL, 0, &len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + keylen = pem.buflen; + } + else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + pem_free( &pem ); + return( ret ); + } + + p = ( ret == 0 ) ? pem.buf : (unsigned char *) key; +#else + p = (unsigned char *) key; +#endif + end = p + keylen; + + /* + * PublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * PublicKey BIT STRING + * } + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { +#if defined(POLARSSL_PEM_C) + pem_free( &pem ); +#endif + rsa_free( rsa ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + if( ( ret = x509_get_pubkey( &p, end, &alg_oid, &rsa->N, &rsa->E ) ) != 0 ) + { +#if defined(POLARSSL_PEM_C) + pem_free( &pem ); +#endif + rsa_free( rsa ); + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + if( ( ret = rsa_check_pubkey( rsa ) ) != 0 ) + { +#if defined(POLARSSL_PEM_C) + pem_free( &pem ); +#endif + rsa_free( rsa ); + return( ret ); + } + + rsa->len = mpi_size( &rsa->N ); + +#if defined(POLARSSL_PEM_C) + pem_free( &pem ); +#endif + + return( 0 ); +} + +#if defined(POLARSSL_DHM_C) +/* + * Parse DHM parameters + */ +int x509parse_dhm( dhm_context *dhm, const unsigned char *dhmin, size_t dhminlen ) +{ + int ret; + size_t len; + unsigned char *p, *end; +#if defined(POLARSSL_PEM_C) + pem_context pem; + + pem_init( &pem ); + + ret = pem_read_buffer( &pem, + "-----BEGIN DH PARAMETERS-----", + "-----END DH PARAMETERS-----", + dhmin, NULL, 0, &dhminlen ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + dhminlen = pem.buflen; + } + else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + pem_free( &pem ); + return( ret ); + } + + p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin; +#else + p = (unsigned char *) dhmin; +#endif + end = p + dhminlen; + + memset( dhm, 0, sizeof( dhm_context ) ); + + /* + * DHParams ::= SEQUENCE { + * prime INTEGER, -- P + * generator INTEGER, -- g + * } + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { +#if defined(POLARSSL_PEM_C) + pem_free( &pem ); +#endif + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = asn1_get_mpi( &p, end, &dhm->P ) ) != 0 || + ( ret = asn1_get_mpi( &p, end, &dhm->G ) ) != 0 ) + { +#if defined(POLARSSL_PEM_C) + pem_free( &pem ); +#endif + dhm_free( dhm ); + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + if( p != end ) + { +#if defined(POLARSSL_PEM_C) + pem_free( &pem ); +#endif + dhm_free( dhm ); + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + +#if defined(POLARSSL_PEM_C) + pem_free( &pem ); +#endif + + return( 0 ); +} + +#if defined(POLARSSL_FS_IO) +/* + * Load and parse a private RSA key + */ +int x509parse_dhmfile( dhm_context *dhm, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if ( ( ret = load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = x509parse_dhm( dhm, buf, n ); + + memset( buf, 0, n + 1 ); + free( buf ); + + return( ret ); +} +#endif /* POLARSSL_FS_IO */ +#endif /* POLARSSL_DHM_C */ + +#if defined _MSC_VER && !defined snprintf +#include + +#if !defined vsnprintf +#define vsnprintf _vsnprintf +#endif // vsnprintf + +/* + * Windows _snprintf and _vsnprintf are not compatible to linux versions. + * Result value is not size of buffer needed, but -1 if no fit is possible. + * + * This fuction tries to 'fix' this by at least suggesting enlarging the + * size by 20. + */ +int compat_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int res = -1; + + va_start( ap, format ); + + res = vsnprintf( str, size, format, ap ); + + va_end( ap ); + + // No quick fix possible + if ( res < 0 ) + return( (int) size + 20 ); + + return res; +} + +#define snprintf compat_snprintf +#endif + +#define POLARSSL_ERR_DEBUG_BUF_TOO_SMALL -2 + +#define SAFE_SNPRINTF() \ +{ \ + if( ret == -1 ) \ + return( -1 ); \ + \ + if ( (unsigned int) ret > n ) { \ + p[n - 1] = '\0'; \ + return POLARSSL_ERR_DEBUG_BUF_TOO_SMALL;\ + } \ + \ + n -= (unsigned int) ret; \ + p += (unsigned int) ret; \ +} + +/* + * Store the name in printable form into buf; no more + * than size characters will be written + */ +int x509parse_dn_gets( char *buf, size_t size, const x509_name *dn ) +{ + int ret; + size_t i, n; + unsigned char c; + const x509_name *name; + char s[128], *p; + + memset( s, 0, sizeof( s ) ); + + name = dn; + p = buf; + n = size; + + while( name != NULL ) + { + if( !name->oid.p ) + { + name = name->next; + continue; + } + + if( name != dn ) + { + ret = snprintf( p, n, ", " ); + SAFE_SNPRINTF(); + } + + if( name->oid.len == 3 && + memcmp( name->oid.p, OID_X520, 2 ) == 0 ) + { + switch( name->oid.p[2] ) + { + case X520_COMMON_NAME: + ret = snprintf( p, n, "CN=" ); break; + + case X520_COUNTRY: + ret = snprintf( p, n, "C=" ); break; + + case X520_LOCALITY: + ret = snprintf( p, n, "L=" ); break; + + case X520_STATE: + ret = snprintf( p, n, "ST=" ); break; + + case X520_ORGANIZATION: + ret = snprintf( p, n, "O=" ); break; + + case X520_ORG_UNIT: + ret = snprintf( p, n, "OU=" ); break; + + default: + ret = snprintf( p, n, "0x%02X=", + name->oid.p[2] ); + break; + } + SAFE_SNPRINTF(); + } + else if( name->oid.len == 9 && + memcmp( name->oid.p, OID_PKCS9, 8 ) == 0 ) + { + switch( name->oid.p[8] ) + { + case PKCS9_EMAIL: + ret = snprintf( p, n, "emailAddress=" ); break; + + default: + ret = snprintf( p, n, "0x%02X=", + name->oid.p[8] ); + break; + } + SAFE_SNPRINTF(); + } + else + { + ret = snprintf( p, n, "\?\?=" ); + SAFE_SNPRINTF(); + } + + for( i = 0; i < name->val.len; i++ ) + { + if( i >= sizeof( s ) - 1 ) + break; + + c = name->val.p[i]; + if( c < 32 || c == 127 || ( c > 128 && c < 160 ) ) + s[i] = '?'; + else s[i] = c; + } + s[i] = '\0'; + ret = snprintf( p, n, "%s", s ); + SAFE_SNPRINTF(); + name = name->next; + } + + return( (int) ( size - n ) ); +} + +/* + * Store the serial in printable form into buf; no more + * than size characters will be written + */ +int x509parse_serial_gets( char *buf, size_t size, const x509_buf *serial ) +{ + int ret; + size_t i, n, nr; + char *p; + + p = buf; + n = size; + + nr = ( serial->len <= 32 ) + ? serial->len : 28; + + for( i = 0; i < nr; i++ ) + { + if( i == 0 && nr > 1 && serial->p[i] == 0x0 ) + continue; + + ret = snprintf( p, n, "%02X%s", + serial->p[i], ( i < nr - 1 ) ? ":" : "" ); + SAFE_SNPRINTF(); + } + + if( nr != serial->len ) + { + ret = snprintf( p, n, "...." ); + SAFE_SNPRINTF(); + } + + return( (int) ( size - n ) ); +} + +/* + * Return an informational string about the certificate. + */ +int x509parse_cert_info( char *buf, size_t size, const char *prefix, + const x509_cert *crt ) +{ + int ret; + size_t n; + char *p; + + p = buf; + n = size; + + ret = snprintf( p, n, "%scert. version : %d\n", + prefix, crt->version ); + SAFE_SNPRINTF(); + ret = snprintf( p, n, "%sserial number : ", + prefix ); + SAFE_SNPRINTF(); + + ret = x509parse_serial_gets( p, n, &crt->serial); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%sissuer name : ", prefix ); + SAFE_SNPRINTF(); + ret = x509parse_dn_gets( p, n, &crt->issuer ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%ssubject name : ", prefix ); + SAFE_SNPRINTF(); + ret = x509parse_dn_gets( p, n, &crt->subject ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%sissued on : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crt->valid_from.year, crt->valid_from.mon, + crt->valid_from.day, crt->valid_from.hour, + crt->valid_from.min, crt->valid_from.sec ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%sexpires on : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crt->valid_to.year, crt->valid_to.mon, + crt->valid_to.day, crt->valid_to.hour, + crt->valid_to.min, crt->valid_to.sec ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%ssigned using : RSA+", prefix ); + SAFE_SNPRINTF(); + + switch( crt->sig_alg ) + { + case SIG_RSA_MD2 : ret = snprintf( p, n, "MD2" ); break; + case SIG_RSA_MD4 : ret = snprintf( p, n, "MD4" ); break; + case SIG_RSA_MD5 : ret = snprintf( p, n, "MD5" ); break; + case SIG_RSA_SHA1 : ret = snprintf( p, n, "SHA1" ); break; + case SIG_RSA_SHA224 : ret = snprintf( p, n, "SHA224" ); break; + case SIG_RSA_SHA256 : ret = snprintf( p, n, "SHA256" ); break; + case SIG_RSA_SHA384 : ret = snprintf( p, n, "SHA384" ); break; + case SIG_RSA_SHA512 : ret = snprintf( p, n, "SHA512" ); break; + default: ret = snprintf( p, n, "???" ); break; + } + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%sRSA key size : %d bits\n", prefix, + (int) crt->rsa.N.n * (int) sizeof( t_uint ) * 8 ); + SAFE_SNPRINTF(); + + return( (int) ( size - n ) ); +} + +/* + * Return an informational string describing the given OID + */ +const char *x509_oid_get_description( x509_buf *oid ) +{ + if ( oid == NULL ) + return ( NULL ); + + else if( OID_CMP( OID_SERVER_AUTH, oid ) ) + return( STRING_SERVER_AUTH ); + + else if( OID_CMP( OID_CLIENT_AUTH, oid ) ) + return( STRING_CLIENT_AUTH ); + + else if( OID_CMP( OID_CODE_SIGNING, oid ) ) + return( STRING_CODE_SIGNING ); + + else if( OID_CMP( OID_EMAIL_PROTECTION, oid ) ) + return( STRING_EMAIL_PROTECTION ); + + else if( OID_CMP( OID_TIME_STAMPING, oid ) ) + return( STRING_TIME_STAMPING ); + + else if( OID_CMP( OID_OCSP_SIGNING, oid ) ) + return( STRING_OCSP_SIGNING ); + + return( NULL ); +} + +/* Return the x.y.z.... style numeric string for the given OID */ +int x509_oid_get_numeric_string( char *buf, size_t size, x509_buf *oid ) +{ + int ret; + size_t i, n; + unsigned int value; + char *p; + + p = buf; + n = size; + + /* First byte contains first two dots */ + if( oid->len > 0 ) + { + ret = snprintf( p, n, "%d.%d", oid->p[0]/40, oid->p[0]%40 ); + SAFE_SNPRINTF(); + } + + /* TODO: value can overflow in value. */ + value = 0; + for( i = 1; i < oid->len; i++ ) + { + value <<= 7; + value += oid->p[i] & 0x7F; + + if( !( oid->p[i] & 0x80 ) ) + { + /* Last byte */ + ret = snprintf( p, n, ".%d", value ); + SAFE_SNPRINTF(); + value = 0; + } + } + + return( (int) ( size - n ) ); +} + +/* + * Return an informational string about the CRL. + */ +int x509parse_crl_info( char *buf, size_t size, const char *prefix, + const x509_crl *crl ) +{ + int ret; + size_t n; + char *p; + const x509_crl_entry *entry; + + p = buf; + n = size; + + ret = snprintf( p, n, "%sCRL version : %d", + prefix, crl->version ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%sissuer name : ", prefix ); + SAFE_SNPRINTF(); + ret = x509parse_dn_gets( p, n, &crl->issuer ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%sthis update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->this_update.year, crl->this_update.mon, + crl->this_update.day, crl->this_update.hour, + crl->this_update.min, crl->this_update.sec ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%snext update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->next_update.year, crl->next_update.mon, + crl->next_update.day, crl->next_update.hour, + crl->next_update.min, crl->next_update.sec ); + SAFE_SNPRINTF(); + + entry = &crl->entry; + + ret = snprintf( p, n, "\n%sRevoked certificates:", + prefix ); + SAFE_SNPRINTF(); + + while( entry != NULL && entry->raw.len != 0 ) + { + ret = snprintf( p, n, "\n%sserial number: ", + prefix ); + SAFE_SNPRINTF(); + + ret = x509parse_serial_gets( p, n, &entry->serial); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, " revocation date: " \ + "%04d-%02d-%02d %02d:%02d:%02d", + entry->revocation_date.year, entry->revocation_date.mon, + entry->revocation_date.day, entry->revocation_date.hour, + entry->revocation_date.min, entry->revocation_date.sec ); + SAFE_SNPRINTF(); + + entry = entry->next; + } + + ret = snprintf( p, n, "\n%ssigned using : RSA+", prefix ); + SAFE_SNPRINTF(); + + switch( crl->sig_alg ) + { + case SIG_RSA_MD2 : ret = snprintf( p, n, "MD2" ); break; + case SIG_RSA_MD4 : ret = snprintf( p, n, "MD4" ); break; + case SIG_RSA_MD5 : ret = snprintf( p, n, "MD5" ); break; + case SIG_RSA_SHA1 : ret = snprintf( p, n, "SHA1" ); break; + case SIG_RSA_SHA224 : ret = snprintf( p, n, "SHA224" ); break; + case SIG_RSA_SHA256 : ret = snprintf( p, n, "SHA256" ); break; + case SIG_RSA_SHA384 : ret = snprintf( p, n, "SHA384" ); break; + case SIG_RSA_SHA512 : ret = snprintf( p, n, "SHA512" ); break; + default: ret = snprintf( p, n, "???" ); break; + } + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n" ); + SAFE_SNPRINTF(); + + return( (int) ( size - n ) ); +} + +/* + * Return 0 if the x509_time is still valid, or 1 otherwise. + */ +int x509parse_time_expired( const x509_time *to ) +{ + int year, mon, day; + int hour, min, sec; + +#if defined(_WIN32) + SYSTEMTIME st; + + GetLocalTime(&st); + + year = st.wYear; + mon = st.wMonth; + day = st.wDay; + hour = st.wHour; + min = st.wMinute; + sec = st.wSecond; +#else + struct tm *lt; + time_t tt; + + tt = time( NULL ); + lt = localtime( &tt ); + + year = lt->tm_year + 1900; + mon = lt->tm_mon + 1; + day = lt->tm_mday; + hour = lt->tm_hour; + min = lt->tm_min; + sec = lt->tm_sec; +#endif + + if( year > to->year ) + return( 1 ); + + if( year == to->year && + mon > to->mon ) + return( 1 ); + + if( year == to->year && + mon == to->mon && + day > to->day ) + return( 1 ); + + if( year == to->year && + mon == to->mon && + day == to->day && + hour > to->hour ) + return( 1 ); + + if( year == to->year && + mon == to->mon && + day == to->day && + hour == to->hour && + min > to->min ) + return( 1 ); + + if( year == to->year && + mon == to->mon && + day == to->day && + hour == to->hour && + min == to->min && + sec > to->sec ) + return( 1 ); + + return( 0 ); +} + +/* + * Return 1 if the certificate is revoked, or 0 otherwise. + */ +int x509parse_revoked( const x509_cert *crt, const x509_crl *crl ) +{ + const x509_crl_entry *cur = &crl->entry; + + while( cur != NULL && cur->serial.len != 0 ) + { + if( crt->serial.len == cur->serial.len && + memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 ) + { + if( x509parse_time_expired( &cur->revocation_date ) ) + return( 1 ); + } + + cur = cur->next; + } + + return( 0 ); +} + +/* + * Wrapper for x509 hashes. + */ +static void x509_hash( const unsigned char *in, size_t len, int alg, + unsigned char *out ) +{ + switch( alg ) + { +#if defined(POLARSSL_MD2_C) + case SIG_RSA_MD2 : md2( in, len, out ); break; +#endif +#if defined(POLARSSL_MD4_C) + case SIG_RSA_MD4 : md4( in, len, out ); break; +#endif +#if defined(POLARSSL_MD5_C) + case SIG_RSA_MD5 : md5( in, len, out ); break; +#endif +#if defined(POLARSSL_SHA1_C) + case SIG_RSA_SHA1 : sha1( in, len, out ); break; +#endif +#if defined(POLARSSL_SHA2_C) + case SIG_RSA_SHA224 : sha2( in, len, out, 1 ); break; + case SIG_RSA_SHA256 : sha2( in, len, out, 0 ); break; +#endif +#if defined(POLARSSL_SHA4_C) + case SIG_RSA_SHA384 : sha4( in, len, out, 1 ); break; + case SIG_RSA_SHA512 : sha4( in, len, out, 0 ); break; +#endif + default: + memset( out, '\xFF', 64 ); + break; + } +} + +/* + * Check that the given certificate is valid accoring to the CRL. + */ +static int x509parse_verifycrl(x509_cert *crt, x509_cert *ca, + x509_crl *crl_list) +{ + int flags = 0; + int hash_id; + unsigned char hash[64]; + + if( ca == NULL ) + return( flags ); + + /* + * TODO: What happens if no CRL is present? + * Suggestion: Revocation state should be unknown if no CRL is present. + * For backwards compatibility this is not yet implemented. + */ + + while( crl_list != NULL ) + { + if( crl_list->version == 0 || + crl_list->issuer_raw.len != ca->subject_raw.len || + memcmp( crl_list->issuer_raw.p, ca->subject_raw.p, + crl_list->issuer_raw.len ) != 0 ) + { + crl_list = crl_list->next; + continue; + } + + /* + * Check if CRL is correctly signed by the trusted CA + */ + hash_id = crl_list->sig_alg; + + x509_hash( crl_list->tbs.p, crl_list->tbs.len, hash_id, hash ); + + if( !rsa_pkcs1_verify( &ca->rsa, RSA_PUBLIC, hash_id, + 0, hash, crl_list->sig.p ) == 0 ) + { + /* + * CRL is not trusted + */ + flags |= BADCRL_NOT_TRUSTED; + break; + } + + /* + * Check for validity of CRL (Do not drop out) + */ + if( x509parse_time_expired( &crl_list->next_update ) ) + flags |= BADCRL_EXPIRED; + + /* + * Check if certificate is revoked + */ + if( x509parse_revoked(crt, crl_list) ) + { + flags |= BADCERT_REVOKED; + break; + } + + crl_list = crl_list->next; + } + return flags; +} + +int x509_wildcard_verify( const char *cn, x509_buf *name ) +{ + size_t i; + size_t cn_idx = 0; + + if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' ) + return( 0 ); + + for( i = 0; i < strlen( cn ); ++i ) + { + if( cn[i] == '.' ) + { + cn_idx = i; + break; + } + } + + if( cn_idx == 0 ) + return( 0 ); + + if( strlen( cn ) - cn_idx == name->len - 1 && + memcmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static int x509parse_verify_top( + x509_cert *child, x509_cert *trust_ca, + x509_crl *ca_crl, int path_cnt, int *flags, + int (*f_vrfy)(void *, x509_cert *, int, int *), + void *p_vrfy ) +{ + int hash_id, ret; + int ca_flags = 0, check_path_cnt = path_cnt + 1; + unsigned char hash[64]; + + if( x509parse_time_expired( &child->valid_to ) ) + *flags |= BADCERT_EXPIRED; + + /* + * Child is the top of the chain. Check against the trust_ca list. + */ + *flags |= BADCERT_NOT_TRUSTED; + + while( trust_ca != NULL ) + { + if( trust_ca->version == 0 || + child->issuer_raw.len != trust_ca->subject_raw.len || + memcmp( child->issuer_raw.p, trust_ca->subject_raw.p, + child->issuer_raw.len ) != 0 ) + { + trust_ca = trust_ca->next; + continue; + } + + /* + * Reduce path_len to check against if top of the chain is + * the same as the trusted CA + */ + if( child->subject_raw.len == trust_ca->subject_raw.len && + memcmp( child->subject_raw.p, trust_ca->subject_raw.p, + child->issuer_raw.len ) == 0 ) + { + check_path_cnt--; + } + + if( trust_ca->max_pathlen > 0 && + trust_ca->max_pathlen < check_path_cnt ) + { + trust_ca = trust_ca->next; + continue; + } + + hash_id = child->sig_alg; + + x509_hash( child->tbs.p, child->tbs.len, hash_id, hash ); + + if( rsa_pkcs1_verify( &trust_ca->rsa, RSA_PUBLIC, hash_id, + 0, hash, child->sig.p ) != 0 ) + { + trust_ca = trust_ca->next; + continue; + } + + /* + * Top of chain is signed by a trusted CA + */ + *flags &= ~BADCERT_NOT_TRUSTED; + break; + } + + /* + * If top of chain is not the same as the trusted CA send a verify request + * to the callback for any issues with validity and CRL presence for the + * trusted CA certificate. + */ + if( trust_ca != NULL && + ( child->subject_raw.len != trust_ca->subject_raw.len || + memcmp( child->subject_raw.p, trust_ca->subject_raw.p, + child->issuer_raw.len ) != 0 ) ) + { + /* Check trusted CA's CRL for then chain's top crt */ + *flags |= x509parse_verifycrl( child, trust_ca, ca_crl ); + + if( x509parse_time_expired( &trust_ca->valid_to ) ) + ca_flags |= BADCERT_EXPIRED; + + if( NULL != f_vrfy ) + { + if( ( ret = f_vrfy( p_vrfy, trust_ca, path_cnt + 1, &ca_flags ) ) != 0 ) + return( ret ); + } + } + + /* Call callback on top cert */ + if( NULL != f_vrfy ) + { + if( ( ret = f_vrfy(p_vrfy, child, path_cnt, flags ) ) != 0 ) + return( ret ); + } + + *flags |= ca_flags; + + return( 0 ); +} + +static int x509parse_verify_child( + x509_cert *child, x509_cert *parent, x509_cert *trust_ca, + x509_crl *ca_crl, int path_cnt, int *flags, + int (*f_vrfy)(void *, x509_cert *, int, int *), + void *p_vrfy ) +{ + int hash_id, ret; + int parent_flags = 0; + unsigned char hash[64]; + x509_cert *grandparent; + + if( x509parse_time_expired( &child->valid_to ) ) + *flags |= BADCERT_EXPIRED; + + hash_id = child->sig_alg; + + x509_hash( child->tbs.p, child->tbs.len, hash_id, hash ); + + if( rsa_pkcs1_verify( &parent->rsa, RSA_PUBLIC, hash_id, 0, hash, + child->sig.p ) != 0 ) + *flags |= BADCERT_NOT_TRUSTED; + + /* Check trusted CA's CRL for the given crt */ + *flags |= x509parse_verifycrl(child, parent, ca_crl); + + grandparent = parent->next; + + while( grandparent != NULL ) + { + if( grandparent->version == 0 || + grandparent->ca_istrue == 0 || + parent->issuer_raw.len != grandparent->subject_raw.len || + memcmp( parent->issuer_raw.p, grandparent->subject_raw.p, + parent->issuer_raw.len ) != 0 ) + { + grandparent = grandparent->next; + continue; + } + break; + } + + if( grandparent != NULL ) + { + /* + * Part of the chain + */ + ret = x509parse_verify_child( parent, grandparent, trust_ca, ca_crl, path_cnt + 1, &parent_flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + ret = x509parse_verify_top( parent, trust_ca, ca_crl, path_cnt + 1, &parent_flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + + /* child is verified to be a child of the parent, call verify callback */ + if( NULL != f_vrfy ) + if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 ) + return( ret ); + + *flags |= parent_flags; + + return( 0 ); +} + +/* + * Verify the certificate validity + */ +int x509parse_verify( x509_cert *crt, + x509_cert *trust_ca, + x509_crl *ca_crl, + const char *cn, int *flags, + int (*f_vrfy)(void *, x509_cert *, int, int *), + void *p_vrfy ) +{ + size_t cn_len; + int ret; + int pathlen = 0; + x509_cert *parent; + x509_name *name; + x509_sequence *cur = NULL; + + *flags = 0; + + if( cn != NULL ) + { + name = &crt->subject; + cn_len = strlen( cn ); + + if( crt->ext_types & EXT_SUBJECT_ALT_NAME ) + { + cur = &crt->subject_alt_names; + + while( cur != NULL ) + { + if( cur->buf.len == cn_len && + memcmp( cn, cur->buf.p, cn_len ) == 0 ) + break; + + if( cur->buf.len > 2 && + memcmp( cur->buf.p, "*.", 2 ) == 0 && + x509_wildcard_verify( cn, &cur->buf ) ) + break; + + cur = cur->next; + } + + if( cur == NULL ) + *flags |= BADCERT_CN_MISMATCH; + } + else + { + while( name != NULL ) + { + if( name->oid.len == 3 && + memcmp( name->oid.p, OID_CN, 3 ) == 0 ) + { + if( name->val.len == cn_len && + memcmp( name->val.p, cn, cn_len ) == 0 ) + break; + + if( name->val.len > 2 && + memcmp( name->val.p, "*.", 2 ) == 0 && + x509_wildcard_verify( cn, &name->val ) ) + break; + } + + name = name->next; + } + + if( name == NULL ) + *flags |= BADCERT_CN_MISMATCH; + } + } + + /* + * Iterate upwards in the given cert chain, to find our crt parent. + * Ignore any upper cert with CA != TRUE. + */ + parent = crt->next; + + while( parent != NULL && parent->version != 0 ) + { + if( parent->ca_istrue == 0 || + crt->issuer_raw.len != parent->subject_raw.len || + memcmp( crt->issuer_raw.p, parent->subject_raw.p, + crt->issuer_raw.len ) != 0 ) + { + parent = parent->next; + continue; + } + break; + } + + if( parent != NULL ) + { + /* + * Part of the chain + */ + ret = x509parse_verify_child( crt, parent, trust_ca, ca_crl, pathlen, flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + ret = x509parse_verify_top( crt, trust_ca, ca_crl, pathlen, flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + + if( *flags != 0 ) + return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED ); + + return( 0 ); +} + +/* + * Unallocate all certificate data + */ +void x509_free( x509_cert *crt ) +{ + x509_cert *cert_cur = crt; + x509_cert *cert_prv; + x509_name *name_cur; + x509_name *name_prv; + x509_sequence *seq_cur; + x509_sequence *seq_prv; + + if( crt == NULL ) + return; + + do + { + rsa_free( &cert_cur->rsa ); + + name_cur = cert_cur->issuer.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + memset( name_prv, 0, sizeof( x509_name ) ); + free( name_prv ); + } + + name_cur = cert_cur->subject.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + memset( name_prv, 0, sizeof( x509_name ) ); + free( name_prv ); + } + + seq_cur = cert_cur->ext_key_usage.next; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + memset( seq_prv, 0, sizeof( x509_sequence ) ); + free( seq_prv ); + } + + seq_cur = cert_cur->subject_alt_names.next; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + memset( seq_prv, 0, sizeof( x509_sequence ) ); + free( seq_prv ); + } + + if( cert_cur->raw.p != NULL ) + { + memset( cert_cur->raw.p, 0, cert_cur->raw.len ); + free( cert_cur->raw.p ); + } + + cert_cur = cert_cur->next; + } + while( cert_cur != NULL ); + + cert_cur = crt; + do + { + cert_prv = cert_cur; + cert_cur = cert_cur->next; + + memset( cert_prv, 0, sizeof( x509_cert ) ); + if( cert_prv != crt ) + free( cert_prv ); + } + while( cert_cur != NULL ); +} + +/* + * Unallocate all CRL data + */ +void x509_crl_free( x509_crl *crl ) +{ + x509_crl *crl_cur = crl; + x509_crl *crl_prv; + x509_name *name_cur; + x509_name *name_prv; + x509_crl_entry *entry_cur; + x509_crl_entry *entry_prv; + + if( crl == NULL ) + return; + + do + { + name_cur = crl_cur->issuer.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + memset( name_prv, 0, sizeof( x509_name ) ); + free( name_prv ); + } + + entry_cur = crl_cur->entry.next; + while( entry_cur != NULL ) + { + entry_prv = entry_cur; + entry_cur = entry_cur->next; + memset( entry_prv, 0, sizeof( x509_crl_entry ) ); + free( entry_prv ); + } + + if( crl_cur->raw.p != NULL ) + { + memset( crl_cur->raw.p, 0, crl_cur->raw.len ); + free( crl_cur->raw.p ); + } + + crl_cur = crl_cur->next; + } + while( crl_cur != NULL ); + + crl_cur = crl; + do + { + crl_prv = crl_cur; + crl_cur = crl_cur->next; + + memset( crl_prv, 0, sizeof( x509_crl ) ); + if( crl_prv != crl ) + free( crl_prv ); + } + while( crl_cur != NULL ); +} + +#if defined(POLARSSL_SELF_TEST) + +#include "certs.h" + +/* + * Checkup routine + */ +int x509_self_test( int verbose ) +{ +#if defined(POLARSSL_CERTS_C) && defined(POLARSSL_MD5_C) + int ret; + int flags; + size_t i, j; + x509_cert cacert; + x509_cert clicert; + rsa_context rsa; +#if defined(POLARSSL_DHM_C) + dhm_context dhm; +#endif + + if( verbose != 0 ) + printf( " X.509 certificate load: " ); + + memset( &clicert, 0, sizeof( x509_cert ) ); + + ret = x509parse_crt( &clicert, (const unsigned char *) test_cli_crt, + strlen( test_cli_crt ) ); + if( ret != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( ret ); + } + + memset( &cacert, 0, sizeof( x509_cert ) ); + + ret = x509parse_crt( &cacert, (const unsigned char *) test_ca_crt, + strlen( test_ca_crt ) ); + if( ret != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( ret ); + } + + if( verbose != 0 ) + printf( "passed\n X.509 private key load: " ); + + i = strlen( test_ca_key ); + j = strlen( test_ca_pwd ); + + rsa_init( &rsa, RSA_PKCS_V15, 0 ); + + if( ( ret = x509parse_key( &rsa, + (const unsigned char *) test_ca_key, i, + (const unsigned char *) test_ca_pwd, j ) ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( ret ); + } + + if( verbose != 0 ) + printf( "passed\n X.509 signature verify: "); + + ret = x509parse_verify( &clicert, &cacert, NULL, "PolarSSL Client 2", &flags, NULL, NULL ); + if( ret != 0 ) + { + printf("%02x", flags); + if( verbose != 0 ) + printf( "failed\n" ); + + return( ret ); + } + +#if defined(POLARSSL_DHM_C) + if( verbose != 0 ) + printf( "passed\n X.509 DHM parameter load: " ); + + i = strlen( test_dhm_params ); + j = strlen( test_ca_pwd ); + + if( ( ret = x509parse_dhm( &dhm, (const unsigned char *) test_dhm_params, i ) ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( ret ); + } + + if( verbose != 0 ) + printf( "passed\n\n" ); +#endif + + x509_free( &cacert ); + x509_free( &clicert ); + rsa_free( &rsa ); +#if defined(POLARSSL_DHM_C) + dhm_free( &dhm ); +#endif + + return( 0 ); +#else + ((void) verbose); + return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE ); +#endif +} + +#endif + +#endif diff --git a/src/libpolarssl/x509write.c b/src/libpolarssl/x509write.c new file mode 100644 index 0000000..e88f6e8 --- /dev/null +++ b/src/libpolarssl/x509write.c @@ -0,0 +1,1141 @@ +/* + * X.509 certificate and private key writing + * + * Copyright (C) 2006-2007 Pascal Vizeli + * Modifications (C) 2009 Steven Barth + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License, version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +/* + * The ITU-T X.509 standard defines a certificat format for PKI. + * + * http://www.ietf.org/rfc/rfc2459.txt + * http://www.ietf.org/rfc/rfc3279.txt + * + * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + * + * For CRS: + * http://www.faqs.org/rfcs/rfc2314.html + */ +#include "config.h" +#include "x509.h" +#include "base64.h" +#include "sha1.h" +#include "x509write.h" + +#include +#include +#include +#include +#include + +#define and && +#define or || + +#if defined _MSC_VER && !defined snprintf +#define snprintf _snprintf +#endif + +static int x509write_realloc_node(x509_node *node, size_t larger); +static int x509write_file(x509_node *node, char *path, int format, const char* pem_prolog, const char* pem_epilog); + +/* + * evaluate how mani octet have this integer + */ +static int asn1_eval_octet(unsigned int digit) +{ + int i, byte; + + for (byte = 4, i = 24; i >= 0; i -= 8, --byte) + if (((digit >> i) & 0xFF) != 0) + return byte; + + return 0; +} + +/* + * write the asn.1 lenght form into p + */ +static int asn1_add_len(unsigned int size, x509_node *node) +{ + if (size > 127) { + + /* long size */ + int byte = asn1_eval_octet(size); + int i = 0; + + *(node->p) = (0x80 | byte) & 0xFF; + ++node->p; + + for (i = byte; i > 0; --i) { + + *(node->p) = (size >> ((i - 1) * 8)) & 0xFF; + ++node->p; + } + + } else { + + /* short size */ + *(node->p) = size & 0xFF; + if (size != 0) + ++node->p; + } + + return 0; +} + +/* + * write a ans.1 object into p + */ +static int asn1_add_obj(unsigned char *value, unsigned int size, int tag, + x509_node *node) +{ + int tl = 2; + + if (tag == ASN1_BIT_STRING) + ++tl; + + if (size > 127) + x509write_realloc_node(node, (size_t) size + tl + + asn1_eval_octet(size)); + else + x509write_realloc_node(node, (size_t) size + tl); + + if (node->data == NULL) + return 1; + + /* tag */ + *(node->p) = tag & 0xFF; + ++node->p; + + /* len */ + if (tag == ASN1_BIT_STRING) { + asn1_add_len((unsigned int) size + 1, node); + *(node->p) = 0x00; + ++node->p; + } else { + asn1_add_len((unsigned int) size, node); + } + + /* value */ + if (size > 0) { + + memcpy(node->p, value, (size_t) size); + if ((node->p += size -1) != node->end) + return POLARSSL_ERR_X509_POINT_ERROR; + } else { + /* make nothing -> NULL */ + } + + return 0; +} + +/* + * write a asn.1 conform integer object + */ +static int asn1_add_int(signed int value, x509_node *node) +{ + signed int i = 0, neg = 1; + unsigned int byte, u_val = 0, tmp_val = 0; + + /* if negate? */ + if (value < 0) { + neg = -1; + u_val = ~value; + } else { + u_val = value; + } + + byte = asn1_eval_octet(u_val); + /* 0 isn't NULL */ + if (byte == 0) + byte = 1; + + /* ASN.1 integer is signed! */ + if (byte < 4 and ((u_val >> ((byte -1) * 8)) & 0xFF) == 0x80) + byte += 1; + + if (x509write_realloc_node(node, (size_t) byte + 2) != 0) + return 1; + + /* tag */ + *(node->p) = ASN1_INTEGER; + ++node->p; + + /* len */ + asn1_add_len(byte, node); + + /* value */ + for (i = byte; i > 0; --i) { + + tmp_val = (u_val >> ((i - 1) * 8)) & 0xFF; + if (neg == 1) + *(node->p) = tmp_val; + else + *(node->p) = ~tmp_val; + + if (i > 1) + ++node->p; + } + + if (node->p != node->end) + return POLARSSL_ERR_X509_POINT_ERROR; + + return 0; +} + +/* + * write a asn.1 conform mpi object + */ +static int asn1_add_mpi(mpi *value, int tag, x509_node *node) +{ + size_t size = (mpi_msb(value) / 8) + 1; + unsigned char *buf; + int buf_len = (int) size, tl = 2; + + if (tag == ASN1_BIT_STRING) + ++tl; + + if (size > 127) + x509write_realloc_node(node, size + (size_t) tl + + asn1_eval_octet((unsigned int)size)); + else + x509write_realloc_node(node, size + (size_t) tl); + + if (node->data == NULL) + return 1; + + buf = (unsigned char*) malloc(size); + if (mpi_write_binary(value, buf, buf_len) != 0) + return POLARSSL_ERR_MPI_BUFFER_TOO_SMALL; + + /* tag */ + *(node->p) = tag & 0xFF; + ++node->p; + + /* len */ + if (tag == ASN1_BIT_STRING) { + asn1_add_len((unsigned int) size + 1, node); + *(node->p) = 0x00; + ++node->p; + } else { + asn1_add_len((unsigned int) size, node); + } + + /* value */ + memcpy(node->p, buf, size); + free(buf); + + if ((node->p += (int) size -1) != node->end) + return POLARSSL_ERR_X509_POINT_ERROR; + + return 0; +} + +/* + * write a node into asn.1 conform object + */ +static int asn1_append_tag(x509_node *node, int tag) +{ + int tl = 2; + + x509_node tmp; + x509write_init_node(&tmp); + + if (tag == ASN1_BIT_STRING) + ++tl; + + if (node->len > 127) + x509write_realloc_node(&tmp, node->len + (size_t) tl + + asn1_eval_octet((unsigned int)node->len)); + else + x509write_realloc_node(&tmp, node->len + (size_t) tl); + + if (tmp.data == NULL) { + x509write_free_node(&tmp); + return 1; + } + + /* tag */ + *(tmp.p) = tag & 0xFF; + ++tmp.p; + + /* len */ + if (tag == ASN1_BIT_STRING) { + asn1_add_len((unsigned int) node->len + 1, &tmp); + *(tmp.p) = 0x00; + ++tmp.p; + } else { + asn1_add_len((unsigned int) node->len, &tmp); + } + + /* value */ + memcpy(tmp.p, node->data, node->len); + + /* good? */ + if ((tmp.p += (int) node->len -1) != tmp.end) { + x509write_free_node(&tmp); + return POLARSSL_ERR_X509_POINT_ERROR; + } + + free(node->data); + node->data = tmp.data; + node->p = tmp.p; + node->end = tmp.end; + node->len = tmp.len; + + return 0; +} + +/* + * write nodes into a asn.1 object + */ +static int asn1_append_nodes(x509_node *node, int tag, int anz, ...) +{ + va_list ap; + size_t size = 0; + x509_node *tmp; + int count; + + va_start(ap, anz); + count = anz; + + while (count--) { + + tmp = va_arg(ap, x509_node*); + if (tmp->data != NULL) + size += tmp->len; + } + + if ( size > 127) { + if (x509write_realloc_node(node, size + (size_t) 2 + + asn1_eval_octet(size)) != 0) + return 1; + } else { + if (x509write_realloc_node(node, size + (size_t) 2) != 0) + return 1; + } + + /* tag */ + *(node->p) = tag & 0xFF; + ++node->p; + + /* len */ + asn1_add_len(size, node); + + /* value */ + va_start(ap, anz); + count = anz; + + while (count--) { + + tmp = va_arg(ap, x509_node*); + if (tmp->data != NULL) { + + memcpy(node->p, tmp->data, tmp->len); + if ((node->p += (int) tmp->len -1) != node->end) + ++node->p; + } + } + + va_end(ap); + return 0; +} + +/* + * write a ASN.1 conform object identifiere include a "tag" + */ +static int asn1_add_oid(x509_node *node, unsigned char *oid, size_t len, + int tag, int tag_val, unsigned char *value, size_t val_len) +{ + int ret; + x509_node tmp; + + x509write_init_node(&tmp); + + /* OBJECT IDENTIFIER */ + if ((ret = asn1_add_obj(oid, len, ASN1_OID, &tmp)) != 0) { + x509write_free_node(&tmp); + return ret; + } + + /* value */ + if ((ret = asn1_add_obj(value, val_len, tag_val, &tmp)) != 0) { + x509write_free_node(&tmp); + return ret; + } + + /* SET/SEQUENCE */ + if ((ret = asn1_append_nodes(node, tag, 1, &tmp)) != 0) { + x509write_free_node(&tmp); + return ret; + } + + x509write_free_node(&tmp); + return 0; +} + +/* + * utcTime UTCTime + */ +static int asn1_add_date_utc(unsigned char *time, x509_node *node) +{ + unsigned char date[13], *sp; + x509_time xtime; + int ret; + + sscanf((char*)time, "%d-%d-%d %d:%d:%d", &xtime.year, &xtime.mon, + &xtime.day, &xtime.hour, &xtime.min, &xtime.sec); + + /* convert to YY */ + if (xtime.year > 2000) + xtime.year -= 2000; + else + xtime.year -= 1900; + + snprintf((char*)date, 13, "%2d%2d%2d%2d%2d%2d", xtime.year, xtime.mon, xtime.day, + xtime.hour, xtime.min, xtime.sec); + + /* replace ' ' to '0' */ + for (sp = date; *sp != '\0'; ++sp) + if (*sp == '\x20') + *sp = '\x30'; + + date[12] = 'Z'; + + if ((ret = asn1_add_obj(date, 13, ASN1_UTC_TIME, node)) != 0) + return ret; + + return 0; +} + +/* + * serialize an rsa key into DER + */ + +int x509write_serialize_key(rsa_context *rsa, x509_node *node) +{ + int ret = 0; + x509write_init_node(node); + + /* vers, n, e, d, p, q, dp, dq, pq */ + if ((ret = asn1_add_int(rsa->ver, node)) != 0) + return ret; + if ((ret = asn1_add_mpi(&rsa->N, ASN1_INTEGER, node)) != 0) + return ret; + if ((ret = asn1_add_mpi(&rsa->E, ASN1_INTEGER, node)) != 0) + return ret; + if ((ret = asn1_add_mpi(&rsa->D, ASN1_INTEGER, node)) != 0) + return ret; + if ((ret = asn1_add_mpi(&rsa->P, ASN1_INTEGER, node)) != 0) + return ret; + if ((ret = asn1_add_mpi(&rsa->Q, ASN1_INTEGER, node)) != 0) + return ret; + if ((ret = asn1_add_mpi(&rsa->DP, ASN1_INTEGER, node)) != 0) + return ret; + if ((ret = asn1_add_mpi(&rsa->DQ, ASN1_INTEGER, node)) != 0) + return ret; + if ((ret = asn1_add_mpi(&rsa->QP, ASN1_INTEGER, node)) != 0) + return ret; + if ((ret = asn1_append_tag(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0) + return ret; + + return 0; +} + +/* + * write a der/pem encoded rsa private key into a file + */ +int x509write_keyfile(rsa_context *rsa, char *path, int out_flag) +{ + int ret = 0; + const char key_beg[] = "-----BEGIN RSA PRIVATE KEY-----\n", + key_end[] = "-----END RSA PRIVATE KEY-----\n"; + x509_node node; + + x509write_init_node(&node); + fprintf(stderr, "x509write_serialize_key()\n"); + if ((ret = x509write_serialize_key(rsa,&node)) != 0) { + x509write_free_node(&node); + return ret; + } + + ret = x509write_file(&node,path,out_flag,key_beg,key_end); + x509write_free_node(&node); + + return ret; +} + + +/* + * reasize the memory for node + */ +static int x509write_realloc_node(x509_node *node, size_t larger) +{ + /* init len */ + if (node->data == NULL) { + node->len = 0; + node->data = malloc(larger); + if(node->data == NULL) + return 1; + } else { + /* realloc memory */ + if ((node->data = realloc(node->data, node->len + larger)) == NULL) + return 1; + } + + /* init pointer */ + node->p = &node->data[node->len]; + node->len += larger; + node->end = &node->data[node->len -1]; + + return 0; +} + +/* + * init node + */ +void x509write_init_node(x509_node *node) +{ + memset(node, 0, sizeof(x509_node)); +} + +/* + * clean memory + */ +void x509write_free_node(x509_node *node) +{ + if (node->data != NULL) + free(node->data); + node->p = NULL; + node->end = NULL; + node->len = 0; +} + +/* + * write a x509 certificate into file + */ +int x509write_crtfile(x509_raw *chain, char *path, int out_flag) +{ + const char cer_beg[] = "-----BEGIN CERTIFICATE-----\n", + cer_end[] = "-----END CERTIFICATE-----\n"; + + return x509write_file(&chain->raw, path, out_flag, cer_beg, cer_end); +} + +/* + * write a x509 certificate into file + */ +int x509write_csrfile(x509_raw *chain, unsigned char *path, int out_flag) +{ + const char cer_beg[] = "-----BEGIN CERTIFICATE REQUEST-----\n", + cer_end[] = "-----END CERTIFICATE REQUEST-----\n"; + + return x509write_file(&chain->raw, (char*)path, out_flag, cer_beg, cer_end); +} + +/* + * write an x509 file + */ +static int x509write_file(x509_node *node, char *path, int format, + const char* pem_prolog, const char* pem_epilog) +{ + FILE *ofstream = stdout; + int is_err = 1, i, n; + size_t buf_len; + unsigned char* base_buf; + + if (path) { + if ((ofstream = fopen(path, "wb")) == NULL) + return 1; + } + + switch (format) { + case X509_OUTPUT_DER: + if (fwrite(node->data, 1, node->len, ofstream) + != node->len) + is_err = -1; + break; + + case X509_OUTPUT_PEM: + if (fprintf(ofstream,pem_prolog)<0) { + is_err = -1; + break; + } + + buf_len = node->len << 1; + base_buf = (unsigned char*) malloc((size_t)buf_len); + memset(base_buf,0,buf_len); + if (base64_encode(base_buf, &buf_len, node->data, + (int) node->len) != 0) { + is_err = -1; + break; + } + + n=strlen((char*)base_buf); + for(i=0;isubpubkey; + + x509write_init_node(&n_tmp); + x509write_init_node(&n_tmp2); + + /* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ + if ((ret = asn1_add_mpi(&pubkey->N, ASN1_INTEGER, &n_tmp)) != 0) { + x509write_free_node(&n_tmp); + x509write_free_node(&n_tmp2); + return ret; + } + if ((ret = asn1_add_mpi(&pubkey->E, ASN1_INTEGER, &n_tmp)) != 0) { + x509write_free_node(&n_tmp); + x509write_free_node(&n_tmp2); + return ret; + } + if ((ret = asn1_append_tag(&n_tmp, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) + != 0) { + x509write_free_node(&n_tmp); + x509write_free_node(&n_tmp2); + return ret; + } + + /* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ + if ((ret = asn1_append_tag(&n_tmp, ASN1_BIT_STRING)) != 0) { + x509write_free_node(&n_tmp); + x509write_free_node(&n_tmp2); + return ret; + } + if ((ret = asn1_add_oid(&n_tmp2, (unsigned char*)OID_PKCS1_RSA, 9, + ASN1_CONSTRUCTED | ASN1_SEQUENCE, ASN1_NULL, + (unsigned char *)"", 0)) != 0) { + x509write_free_node(&n_tmp); + x509write_free_node(&n_tmp2); + return ret; + } + + if ((ret = asn1_append_nodes(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE, 2, + &n_tmp2, &n_tmp))) { + x509write_free_node(&n_tmp); + x509write_free_node(&n_tmp2); + return ret; + } + + x509write_free_node(&n_tmp); + x509write_free_node(&n_tmp2); + return 0; +} + +/* + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + */ +static int x509write_add_name(x509_node *node, unsigned char *oid, + unsigned int oid_len, unsigned char *value, int len, int value_tag) +{ + int ret; + x509_node n_tmp; + + x509write_init_node(&n_tmp); + + if ((ret = asn1_add_oid(&n_tmp, oid, oid_len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE, value_tag, + value, len))) { + x509write_free_node(&n_tmp); + return ret; + } + + if ((asn1_append_nodes(node, ASN1_CONSTRUCTED | ASN1_SET, 1, &n_tmp)) + != 0) { + x509write_free_node(&n_tmp); + return ret; + } + + x509write_free_node(&n_tmp); + return 0; +} + +/* + * Parse the name string and add to node + */ +static int x509write_parse_names(x509_node *node, unsigned char *names) +{ + unsigned char *sp, *begin = NULL; + unsigned char oid[3] = OID_X520, tag[4], *tag_sp = tag; + unsigned char *C = NULL, *CN = NULL, *O = NULL, *OU = NULL, + *ST = NULL, *L = NULL, *R = NULL; + int C_len = 0, CN_len = 0, O_len = 0, OU_len = 0, ST_len = 0, + L_len = 0, R_len = 0; + int ret = 0, is_tag = 1, is_begin = -1, len = 0; + + + for (sp = names; ; ++sp) { + + /* filter tag */ + if (is_tag == 1) { + + if (tag_sp == &tag[3]) + return POLARSSL_ERR_X509_VALUE_TO_LENGTH; + + /* is tag end? */ + if (*sp == '=') { + is_tag = -1; + *tag_sp = '\0'; + is_begin = 1; + /* set len 0 (reset) */ + len = 0; + } else { + /* tag hasn't ' '! */ + if (*sp != ' ') { + *tag_sp = *sp; + ++tag_sp; + } + } + /* filter value */ + } else { + + /* set pointer of value begin */ + if (is_begin == 1) { + begin = sp; + is_begin = -1; + } + + /* is value at end? */ + if (*sp == ';' or *sp == '\0') { + is_tag = 1; + + /* common name */ + if (tag[0] == 'C' and tag[1] == 'N') { + CN = begin; + CN_len = len; + + /* organization */ + } else if (tag[0] == 'O' and tag[1] == '\0') { + O = begin; + O_len = len; + + /* country */ + } else if (tag[0] == 'C' and tag[1] == '\0') { + C = begin; + C_len = len; + + /* organisation unit */ + } else if (tag[0] == 'O' and tag[1] == 'U') { + OU = begin; + OU_len = len; + + /* state */ + } else if (tag[0] == 'S' and tag[1] == 'T') { + ST = begin; + ST_len = len; + + /* locality */ + } else if (tag[0] == 'L' and tag[1] == '\0') { + L = begin; + L_len = len; + + /* email */ + } else if (tag[0] == 'R' and tag[1] == '\0') { + R = begin; + R_len = len; + } + + /* set tag poiner to begin */ + tag_sp = tag; + + /* is at end? */ + if (*sp == '\0' or *(sp +1) == '\0') + break; + } else { + ++len; + } + } + + /* make saver */ + if (*sp == '\0') + break; + } /* end for */ + + /* country */ + if (C != NULL) { + oid[2] = X520_COUNTRY; + if ((ret = x509write_add_name(node, oid, 3, C, C_len, + ASN1_PRINTABLE_STRING)) != 0) + return ret; + } + + /* state */ + if (ST != NULL) { + oid[2] = X520_STATE; + if ((ret = x509write_add_name(node, oid, 3, ST, ST_len, + ASN1_PRINTABLE_STRING)) != 0) + return ret; + } + + /* locality */ + if (L != NULL) { + oid[2] = X520_LOCALITY; + if ((ret = x509write_add_name(node, oid, 3, L, L_len, + ASN1_PRINTABLE_STRING)) != 0) + return ret; + } + + /* organization */ + if (O != NULL) { + oid[2] = X520_ORGANIZATION; + if ((ret = x509write_add_name(node, oid, 3, O, O_len, + ASN1_PRINTABLE_STRING)) != 0) + return ret; + } + + /* organisation unit */ + if (OU != NULL) { + oid[2] = X520_ORG_UNIT; + if ((ret = x509write_add_name(node, oid, 3, OU, OU_len, + ASN1_PRINTABLE_STRING)) != 0) + return ret; + } + + /* common name */ + if (CN != NULL) { + oid[2] = X520_COMMON_NAME; + if ((ret = x509write_add_name(node, oid, 3, CN, CN_len, + ASN1_PRINTABLE_STRING)) != 0) + return ret; + } + + /* email */ + if (R != NULL) { + if ((ret = x509write_add_name(node, (unsigned char*)OID_PKCS9_EMAIL, + 9, R, R_len, ASN1_IA5_STRING)) != 0) + return ret; + } + + if ((asn1_append_tag(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0) + return ret; + + return 0; +} + +/* + * Copy raw data from orginal ca to node + */ +static int x509write_copy_from_raw(x509_node *node, x509_buf *raw) +{ + if (x509write_realloc_node(node, raw->len) != 0) + return 1; + + memcpy(node->p, raw->p, (size_t)raw->len); + if ((node->p += raw->len -1) != node->end) + return POLARSSL_ERR_X509_POINT_ERROR; + + return 0; +} + +/* + * Add the issuer + */ + +int x509write_add_issuer(x509_raw *crt, unsigned char *issuer) +{ + return x509write_parse_names(&crt->issuer, issuer); +} + +/* + * Add the subject + */ +int x509write_add_subject(x509_raw *crt, unsigned char *subject) +{ + return x509write_parse_names(&crt->subject, subject); +} + +/* + * Copy issuer line from another cert to issuer + */ +int x509write_copy_issuer(x509_raw *crt, x509_cert *from_crt) +{ + return x509write_copy_from_raw(&crt->issuer, &from_crt->issuer_raw); +} + +/* + * Copy subject line from another cert + */ +int x509write_copy_subject(x509_raw *crt, x509_cert *from_crt) +{ + return x509write_copy_from_raw(&crt->subject, &from_crt->subject_raw); +} + +/* + * Copy subject line form antoher cert into issuer + */ +int x509write_copy_issuer_from_subject(x509_raw *crt, + x509_cert *from_crt) +{ + return x509write_copy_from_raw(&crt->issuer, &from_crt->subject_raw); +} + +/* + * Copy issuer line from another cert into subject + */ +int x509write_copy_subject_from_issuer(x509_raw *crt, + x509_cert * from_crt) +{ + return x509write_copy_from_raw(&crt->subject, &from_crt->issuer_raw); +} + +/* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + * + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + */ +/* TODO: No handle GeneralizedTime! */ +int x509write_add_validity(x509_raw *chain, unsigned char *befor, + unsigned char *after) +{ + int ret; + + x509_node *node = &chain->validity; + + /* notBefore */ + if ((ret = asn1_add_date_utc(befor, node)) != 0) + return ret; + + /* notAfter */ + if ((ret = asn1_add_date_utc(after, node)) != 0) + return ret; + + if ((ret = asn1_append_tag(node, ASN1_CONSTRUCTED | ASN1_SEQUENCE)) != 0) + return ret; + + return 0; +} + +/* + * make hash from tbs and sign that with private key + */ +static int x509write_make_sign(x509_raw *chain, rsa_context *privkey) +{ + int ret; + unsigned char hash[20], *sign; + size_t sign_len = (size_t) mpi_size(&privkey->N); + + /* make hash */ + sha1(chain->tbs.data, chain->tbs.len, hash); + + /* create sign */ + sign = (unsigned char *) malloc(sign_len); + if (sign == NULL) + return 1; + + if ((ret = rsa_pkcs1_sign(privkey, NULL, NULL, RSA_PRIVATE, SIG_RSA_SHA1, 20, hash, sign)) != 0) + return ret; + + if ((ret = asn1_add_obj(sign, sign_len, ASN1_BIT_STRING, + &chain->sign)) != 0) + return ret; + + /* + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + */ + return asn1_add_oid(&chain->signalg, (unsigned char*)OID_PKCS1_RSA_SHA, 9, + ASN1_CONSTRUCTED | ASN1_SEQUENCE, ASN1_NULL, + (unsigned char*)"", 0); +} + +/* + * Create a self signed certificate + */ +int x509write_create_sign(x509_raw *chain, rsa_context *privkey) +{ + int ret, serial; + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + if ((ret = asn1_add_int(2, &chain->version)) != 0) + return ret; + + if ((ret = asn1_append_tag(&chain->version, ASN1_CONTEXT_SPECIFIC | + ASN1_CONSTRUCTED)) != 0) + return ret; + + + /* + * CertificateSerialNumber ::= INTEGER + */ + srand((unsigned int) time(NULL)); + serial = rand(); + if ((ret = asn1_add_int(serial, &chain->serial)) != 0) + return ret; + + /* + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + */ + if ((ret = asn1_add_oid(&chain->tbs_signalg, + (unsigned char*)OID_PKCS1_RSA_SHA, 9, ASN1_CONSTRUCTED | + ASN1_SEQUENCE, ASN1_NULL, (unsigned char*)"", 0)) != 0) + return ret; + + /* + * Create the tbs + */ + if ((ret = asn1_append_nodes(&chain->tbs, ASN1_CONSTRUCTED | + ASN1_SEQUENCE, 7, &chain->version, &chain->serial, + &chain->tbs_signalg, &chain->issuer, &chain->validity, + &chain->subject, &chain->subpubkey)) != 0) + return ret; + + /* make signing */ + if ((ret = x509write_make_sign(chain, privkey)) != 0) + return ret; + + /* finishing */ + if ((ret = asn1_append_nodes(&chain->raw, ASN1_CONSTRUCTED | + ASN1_SEQUENCE, 3, &chain->tbs, &chain->signalg, + &chain->sign)) != 0) + return ret; + + return 0; +} + +int x509write_create_selfsign(x509_raw *chain, rsa_context *privkey) +{ + /* + * On self signed certificate are subject and issuer the same + */ + x509write_free_node(&chain->issuer); + chain->issuer = chain->subject; + return x509write_create_sign(chain, privkey); +} + +/* + * CertificationRequestInfo ::= SEQUENCE { + * version Version, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * attributes [0] IMPLICIT Attributes } + * + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm SignatureAlgorithmIdentifier, + * signature Signature } + * + * It use chain.serail for attributes! + * + */ +int x509write_create_csr(x509_raw *chain, rsa_context *privkey) +{ + int ret; + + /* version ::= INTEGER */ + if ((ret = asn1_add_int(0, &chain->version)) != 0) + return ret; + + /* write attributes */ + if ((ret = asn1_add_obj((unsigned char*)"", 0, ASN1_CONTEXT_SPECIFIC | + ASN1_CONSTRUCTED, &chain->serial)) != 0) + return ret; + + /* create CertificationRequestInfo */ + if ((ret = asn1_append_nodes(&chain->tbs, ASN1_CONSTRUCTED | + ASN1_SEQUENCE, 4, &chain->version, &chain->subject, + &chain->subpubkey, &chain->serial)) != 0) + return ret; + + /* make signing */ + if ((ret = x509write_make_sign(chain, privkey)) != 0) + return ret; + + /* finish */ + if ((ret = asn1_append_nodes(&chain->raw, ASN1_CONSTRUCTED | ASN1_SEQUENCE, + 3, &chain->tbs, &chain->signalg, &chain->sign)) != 0) + return ret; + + return ret; +} + +/* + * Free memory + */ +void x509write_free_raw(x509_raw *chain) +{ + x509write_free_node(&chain->raw); + x509write_free_node(&chain->tbs); + x509write_free_node(&chain->version); + x509write_free_node(&chain->serial); + x509write_free_node(&chain->tbs_signalg); + x509write_free_node(&chain->issuer); + x509write_free_node(&chain->validity); + if (chain->subject.data != chain->issuer.data) + x509write_free_node(&chain->subject); + x509write_free_node(&chain->subpubkey); + x509write_free_node(&chain->signalg); + x509write_free_node(&chain->sign); +} + +void x509write_init_raw(x509_raw *chain) +{ + memset((void *) chain, 0, sizeof(x509_raw)); +} + diff --git a/src/libpolarssl/x509write.h b/src/libpolarssl/x509write.h new file mode 100644 index 0000000..9522ea3 --- /dev/null +++ b/src/libpolarssl/x509write.h @@ -0,0 +1,309 @@ +/** + * \file x509write.h + * + * \brief X509 buffer writing functionality + * + * Copyright (C) 2006-2012, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_X509_WRITE_H +#define POLARSSL_X509_WRITE_H + +#include "rsa.h" +#include "asn1.h" +#include "x509.h" + + +/* +#define POLARSSL_ERR_ASN1_OUT_OF_DATA -0x0014 +#define POLARSSL_ERR_ASN1_UNEXPECTED_TAG -0x0016 +#define POLARSSL_ERR_ASN1_INVALID_LENGTH -0x0018 +#define POLARSSL_ERR_ASN1_LENGTH_MISMATCH -0x001A +#define POLARSSL_ERR_ASN1_INVALID_DATA -0x001C +*/ + +//Does not appear in 1.2.7 Polar x509.h file +#define POLARSSL_ERR_X509_KEY_INVALID_ENC_IV -0x2A01 +#define POLARSSL_ERR_X509_KEY_UNKNOWN_ENC_ALG -0x2A03 +#define POLARSSL_ERR_X509_KEY_PASSWORD_REQUIRED -0x2A05 +#define POLARSSL_ERR_X509_KEY_PASSWORD_MISMATCH -0x2A07 +#define POLARSSL_ERR_X509_POINT_ERROR -0x2A09 +#define POLARSSL_ERR_X509_VALUE_TO_LENGTH -0x2A11 + + +/* + * DER constants + */ +/* +#define ASN1_BOOLEAN 0x01 +#define ASN1_INTEGER 0x02 +#define ASN1_BIT_STRING 0x03 +#define ASN1_OCTET_STRING 0x04 +#define ASN1_NULL 0x05 +#define ASN1_OID 0x06 +#define ASN1_UTF8_STRING 0x0C +#define ASN1_SEQUENCE 0x10 +#define ASN1_SET 0x11 +#define ASN1_PRINTABLE_STRING 0x13 +#define ASN1_T61_STRING 0x14 +#define ASN1_IA5_STRING 0x16 +#define ASN1_UTC_TIME 0x17 +#define ASN1_UNIVERSAL_STRING 0x1C +#define ASN1_BMP_STRING 0x1E +#define ASN1_PRIMITIVE 0x00 +#define ASN1_CONSTRUCTED 0x20 +#define ASN1_CONTEXT_SPECIFIC 0x80 +*/ + +#define OID_PKCS1_RSA_SHA "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05" + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Add a public key to certificate + * + * \param chain points to the raw certificate data + * \param pubkey points to an RSA key + * + * \return 0 if successful, or a specific X509 error code + */ +int x509write_add_pubkey ( x509_raw *chain, rsa_context *pubkey ); + +/** + * \brief Create x509 subject/issuer field to raw certificate + * from string or CA cert. Make string NULL if you will + * use the CA copy function or make CA NULL then used + * the string parse. + * + * \param chain points to the raw certificate data + * \param names a string that can hold (separete with ";"): + * CN=CommonName + * -- O=Organization + * -- OU=OrgUnit + * -- ST=State + * -- L=Locality + * -- R=Email + * -- C=Country + * . Make that NULL if you didn't need that. + * \param flag flag is X509_ISSUER or X509_SUBJECT that defined + * where change + * \param ca the certificate for copy data. Make that NULL if you + * didn't need that. + * \param ca_flag set the ca field from copy to crt + * + * \return 0 if successful, or a specific X509 error code + */ +/* +int x509write_add_customize ( x509_raw *crt, + unsigned char *names, + int flag, + x509_cert *ca, + int ca_flag ); +*/ + +/** +* \brief Add x509 issuer field +* +* \param chain points to the raw certificate data +* \param issuer a string holding (separete with ";"): +* CN=CommonName +* -- O=Organization +* -- OU=OrgUnit +* -- ST=State +* -- L=Locality +* -- R=Email +* -- C=Country +* . Set this to NULL if not needed. +* \return 0 if successful, or a specific X509 error code +*/ +int x509write_add_issuer ( x509_raw *crt, unsigned char *issuer); + +/** + * \brief Add x509 subject field + * + * \param chain points to the raw certificate data + * \param subject a string holding (separete with ";"): + * CN=CommonName + * -- O=Organization + * -- OU=OrgUnit + * -- ST=State + * -- L=Locality + * -- R=Email + * -- C=Country + * . Set this to NULL if not needed. + * \return 0 if successful, or a specific X509 error code + */ +int x509write_add_subject ( x509_raw *crt, unsigned char *subject); + +/** +* \brief Copy x509 issuer field from another certificate +* +* \param chain points to the raw certificate data +* \param from_crt the certificate whose issuer is to be copied. +* \return 0 if successful, or a specific X509 error code +*/ +int x509write_copy_issuer (x509_raw *crt, x509_cert *from_crt); + +/** +* \brief Copy x509 subject field from another certificate +* +* \param chain points to the raw certificate data +* \param from_crt the certificate whose subject is to be copied. +* \return 0 if successful, or a specific X509 error code +*/ +int x509write_copy_subject (x509_raw *crt, x509_cert *from_crt); + +/** +* \brief Copy x509 issuer field from the subject of another certificate +* +* \param chain points to the raw certificate data +* \param from_crt the certificate whose subject is to be copied. +* \return 0 if successful, or a specific X509 error code +*/ +int x509write_copy_issuer_from_subject (x509_raw *crt, x509_cert *from_crt); + +/** +* \brief Copy x509 subject field from the issuer of another certificate +* +* \param chain points to the raw certificate data +* \param from_crt the certificate whose issuer is to be copied. +* \return 0 if successful, or a specific X509 error code +*/ +int x509write_copy_subject_from_issuer (x509_raw *crt, x509_cert *from_crt); + +/** + * \brief Create x509 validity time in UTC + * + * \param chain points to the raw certificate data + * \param before valid not before in format YYYY-MM-DD hh:mm:ss + * \param after valid not after in format YYYY-MM-DD hh:mm:ss + * + * \return 0 if successful, or a specific X509 error code + */ +int x509write_add_validity ( x509_raw *crt, + unsigned char *before, + unsigned char *after ); + +/** + * \brief Create a self-signed certificate + * + * \param chain points to the raw certificate data + * \param rsa a private key to sign the certificate + * + * \return 0 if successful, or a specific X509 error code + */ +int x509write_create_selfsign ( x509_raw *crt, rsa_context *raw ); + +/** + * \brief Create a certificate + * + * \param chain points to the raw certificate data + * \param rsa a private key to sign the certificate + * + * \return 0 if successful, or a specific X509 error code + */ +int x509write_create_sign ( x509_raw *crt, rsa_context *raw ); + +/** + * \brief Serialize an rsa key into DER + * + * \param rsa a rsa key for output + * \param node a x509 node for write into + * + * \return 0 if successful, or a specific X509 error code + */ +int x509write_serialize_key ( rsa_context *rsa, x509_node *node ); + +/** + * \brief Unallocate all raw certificate data + */ +void x509write_free_raw ( x509_raw *crt ); + +/** + * \brief Allocate all raw certificate data + */ +void x509write_init_raw ( x509_raw *crt ); + +/** + * \brief Unallocate all node certificate data + */ +void x509write_free_node ( x509_node *crt_node ); + +/** + * \brief Allocate all node certificate data + */ +void x509write_init_node ( x509_node *crt_node ); + + +/** + * \brief Write a certificate info file + * + * \param chain points to the raw certificate data + * \param path filename to write the certificate to + * \param format X509_OUTPUT_DER or X509_OUTPUT_PEM + * + * \return 0 if successful, or a specific X509 error code + */ +int x509write_crtfile ( x509_raw *chain, + char *path, + int format ); + +/** + * \brief Write a certificate signing request message format file + * + * \param chain points to the raw certificate (with x509write_create_csr) data + * \param path filename to write the certificate to + * \param format X509_OUTPUT_DER or X509_OUTPUT_PEM + * + * \return 0 if successful, or a specific X509 error code + */ +int x509write_csrfile ( x509_raw *chain, + unsigned char *path, + int format ); + +/* + * \brief Write a private RSA key into a file + * + * \param rsa points to an RSA key + * \param path filename to write the key to + * \param format X509_OUTPUT_DER or X509_OUTPUT_PEM + * + * \return 0 if successful, or a specific X509 error code + */ +int x509write_keyfile ( rsa_context *rsa, + char *path, + int format ); + +/** + * \brief Create a certificate signing request + * + * \param chain points to the raw certificate data. Didn't use the + * same chain that u have use for certificate. + * \param privkey a rsa private key + * + * \return 0 if successful, or a specific X509 error code + */ +int x509write_create_csr ( x509_raw *chain, rsa_context *privkey ); + +#endif /* POLARSSL_X509_WRITE_H */ diff --git a/src/libpolarssl/xtea.c b/src/libpolarssl/xtea.c new file mode 100644 index 0000000..f4cf119 --- /dev/null +++ b/src/libpolarssl/xtea.c @@ -0,0 +1,251 @@ +/* + * An 32-bit implementation of the XTEA algorithm + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#if defined(POLARSSL_XTEA_C) + +#include "xtea.h" + +#if !defined(POLARSSL_XTEA_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * XTEA key schedule + */ +void xtea_setup( xtea_context *ctx, unsigned char key[16] ) +{ + int i; + + memset(ctx, 0, sizeof(xtea_context)); + + for( i = 0; i < 4; i++ ) + { + GET_UINT32_BE( ctx->k[i], key, i << 2 ); + } +} + +/* + * XTEA encrypt function + */ +int xtea_crypt_ecb( xtea_context *ctx, int mode, unsigned char input[8], + unsigned char output[8]) +{ + uint32_t *k, v0, v1, i; + + k = ctx->k; + + GET_UINT32_BE( v0, input, 0 ); + GET_UINT32_BE( v1, input, 4 ); + + if( mode == XTEA_ENCRYPT ) + { + uint32_t sum = 0, delta = 0x9E3779B9; + + for( i = 0; i < 32; i++ ) + { + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); + sum += delta; + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]); + } + } + else /* XTEA_DECRYPT */ + { + uint32_t delta = 0x9E3779B9, sum = delta * 32; + + for( i = 0; i < 32; i++ ) + { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]); + sum -= delta; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); + } + } + + PUT_UINT32_BE( v0, output, 0 ); + PUT_UINT32_BE( v1, output, 4 ); + + return( 0 ); +} + +/* + * XTEA-CBC buffer encryption/decryption + */ +int xtea_crypt_cbc( xtea_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + unsigned char *input, + unsigned char *output) +{ + int i; + unsigned char temp[8]; + + if(length % 8) + return( POLARSSL_ERR_XTEA_INVALID_INPUT_LENGTH ); + + if( mode == XTEA_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + xtea_crypt_ecb( ctx, mode, input, output ); + + for(i = 0; i < 8; i++) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + xtea_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* !POLARSSL_XTEA_ALT */ + +#if defined(POLARSSL_SELF_TEST) + +#include +#include + +/* + * XTEA tests vectors (non-official) + */ + +static const unsigned char xtea_test_key[6][16] = +{ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char xtea_test_pt[6][8] = +{ + { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }, + { 0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f }, + { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }, + { 0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55 } +}; + +static const unsigned char xtea_test_ct[6][8] = +{ + { 0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5 }, + { 0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8 }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }, + { 0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5 }, + { 0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 } +}; + +/* + * Checkup routine + */ +int xtea_self_test( int verbose ) +{ + int i; + unsigned char buf[8]; + xtea_context ctx; + + for( i = 0; i < 6; i++ ) + { + if( verbose != 0 ) + printf( " XTEA test #%d: ", i + 1 ); + + memcpy( buf, xtea_test_pt[i], 8 ); + + xtea_setup( &ctx, (unsigned char *) xtea_test_key[i] ); + xtea_crypt_ecb( &ctx, XTEA_ENCRYPT, buf, buf ); + + if( memcmp( buf, xtea_test_ct[i], 8 ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + printf( "passed\n" ); + } + + if( verbose != 0 ) + printf( "\n" ); + + return( 0 ); +} + +#endif + +#endif diff --git a/src/libpolarssl/xtea.h b/src/libpolarssl/xtea.h new file mode 100644 index 0000000..c95cb76 --- /dev/null +++ b/src/libpolarssl/xtea.h @@ -0,0 +1,129 @@ +/** + * \file xtea.h + * + * \brief XTEA block cipher (32-bit) + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef POLARSSL_XTEA_H +#define POLARSSL_XTEA_H + +#include "config.h" + +#include + +#ifdef _MSC_VER +#include +typedef UINT32 uint32_t; +#else +#include +#endif + +#define XTEA_ENCRYPT 1 +#define XTEA_DECRYPT 0 + +#define POLARSSL_ERR_XTEA_INVALID_INPUT_LENGTH -0x0028 /**< The data input has an invalid length. */ + +#if !defined(POLARSSL_XTEA_ALT) +// Regular implementation +// + +/** + * \brief XTEA context structure + */ +typedef struct +{ + uint32_t k[4]; /*!< key */ +} +xtea_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief XTEA key schedule + * + * \param ctx XTEA context to be initialized + * \param key the secret key + */ +void xtea_setup( xtea_context *ctx, unsigned char key[16] ); + +/** + * \brief XTEA cipher function + * + * \param ctx XTEA context + * \param mode XTEA_ENCRYPT or XTEA_DECRYPT + * \param input 8-byte input block + * \param output 8-byte output block + * + * \return 0 if successful + */ +int xtea_crypt_ecb( xtea_context *ctx, + int mode, + unsigned char input[8], + unsigned char output[8] ); + +/** + * \brief XTEA CBC cipher function + * + * \param ctx XTEA context + * \param mode XTEA_ENCRYPT or XTEA_DECRYPT + * \param length the length of input, multiple of 8 + * \param iv initialization vector for CBC mode + * \param input input block + * \param output output block + * + * \return 0 if successful, + * POLARSSL_ERR_XTEA_INVALID_INPUT_LENGTH if the length % 8 != 0 + */ +int xtea_crypt_cbc( xtea_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + unsigned char *input, + unsigned char *output); + +#ifdef __cplusplus +} +#endif + +#else /* POLARSSL_XTEA_ALT */ +#include "xtea_alt.h" +#endif /* POLARSSL_XTEA_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int xtea_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* xtea.h */ diff --git a/src/xstrbuf.c b/src/xstrbuf.c new file mode 100644 index 0000000..5f770ec --- /dev/null +++ b/src/xstrbuf.c @@ -0,0 +1,69 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * Understanding is not required. Only obedience. + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. */ +#include "xstrbuf.h" + +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// <0: error; 0: ok +int xstrbuf_init (xstrbuf_t *b) { + if (b != NULL) { + memset(b, 0, sizeof(*b)); + if ((b->data = malloc(sizeof(char))) == NULL) return -1; + b->size = 1; + b->data[0] = 0; + return 0; + } + return -1; +} + + +// <0: error; 0: ok +int xstrbuf_free (xstrbuf_t *b) { + if (b != NULL) { + if (b->data != NULL) free(b->data); + memset(b, 0, sizeof(*b)); + return 0; + } + return -1; +} + + +// <0: error; 0: ok +int xstrbuf_addc (xstrbuf_t *b, char c) { + if (b != NULL) { + if (b->used+2 >= b->size) { + int newsz = ((b->used+2+0x3ff)|0x3ff)+1; + char *n = realloc(b->data, newsz); + if (n == NULL) return -1; + b->data = n; + b->size = newsz; + } + b->data[b->used++] = c; + b->data[b->used] = 0; + return 0; + } + return -1; +} + + +// <0: error; 0: ok +int xstrbuf_addstr (xstrbuf_t *b, const char *s) { + if (s == NULL) return 0; + if (b != NULL) { + while (*s) { + int res = xstrbuf_addc(b, *s++); + if (res) return res; + } + return 0; + } + return -1; +} diff --git a/src/xstrbuf.h b/src/xstrbuf.h new file mode 100644 index 0000000..d6cec94 --- /dev/null +++ b/src/xstrbuf.h @@ -0,0 +1,43 @@ +/* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar) + * Understanding is not required. Only obedience. + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://sam.zoy.org/wtfpl/COPYING for more details. */ +#ifndef _XSTRBUF_H_ +#define _XSTRBUF_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// string buffer functions +// +typedef struct { + char *data; // malloc()ed + int used; // used bytes in data + int size; // allocated bytes for data +} xstrbuf_t; + + +// <0: error; 0: ok +extern int xstrbuf_init (xstrbuf_t *b); + +// <0: error; 0: ok +extern int xstrbuf_free (xstrbuf_t *b); + +// <0: error; 0: ok +extern int xstrbuf_addc (xstrbuf_t *b, char c); + +// <0: error; 0: ok +extern int xstrbuf_addstr (xstrbuf_t *b, const char *s); + + +#ifdef __cplusplus +} +#endif +#endif -- 2.11.4.GIT