]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - openssl.c
openssl: Assume that openssl allocation functions functions succeed.
[paraslash.git] / openssl.c
index bda5791fc51d1095a6115ecd5c0476852f517a5e..495d83c2bae0671a7f7d9f0e75a89900bfb4cecb 100644 (file)
--- a/openssl.c
+++ b/openssl.c
@@ -11,6 +11,7 @@
 #include <openssl/sha.h>
 #include <openssl/bn.h>
 #include <openssl/aes.h>
+#include <openssl/evp.h>
 
 #include "para.h"
 #include "error.h"
@@ -23,25 +24,27 @@ struct asymmetric_key {
        RSA *rsa;
 };
 
+static int openssl_perror(const char *pfx)
+{
+       unsigned long err = ERR_get_error();
+       PARA_ERROR_LOG("%s: \"%s\"\n", pfx, ERR_reason_error_string(err));
+       return -E_OPENSSL;
+}
+
 void get_random_bytes_or_die(unsigned char *buf, int num)
 {
-       unsigned long err;
+       int ret;
 
-       /* RAND_bytes() returns 1 on success, 0 otherwise. */
-       if (RAND_bytes(buf, num) == 1)
+       if (RAND_bytes(buf, num) == 1) /* success */
                return;
-       err = ERR_get_error();
-       PARA_EMERG_LOG("%s\n", ERR_reason_error_string(err));
+       ret = openssl_perror("RAND_bytes");
+       PARA_EMERG_LOG("%s\n", strerror(-ret));
        exit(EXIT_FAILURE);
 }
 
 /*
- * Read 64 bytes from /dev/urandom and add them to the SSL PRNG. Seed the PRNG
- * used by random(3) with a random seed obtained from SSL. If /dev/urandom is
- * not readable, the function calls exit().
- *
- * \sa RAND_load_file(3), \ref get_random_bytes_or_die(), srandom(3),
- * random(3), \ref para_random().
+ * Read 64 bytes from /dev/urandom and add them to the SSL PRNG. Then seed the
+ * PRNG used by random(3) with a random seed obtained from SSL.
  */
 void crypt_init(void)
 {
@@ -57,7 +60,15 @@ void crypt_init(void)
 
 void crypt_shutdown(void)
 {
+#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
        CRYPTO_cleanup_all_ex_data();
+#endif
+#ifdef HAVE_OPENSSL_THREAD_STOP /* openssl-1.1 or later */
+       OPENSSL_thread_stop();
+#else /* openssl-1.0 */
+       ERR_remove_thread_state(NULL);
+#endif
+       EVP_cleanup();
 }
 
 /*
@@ -92,16 +103,15 @@ static int read_bignum(const unsigned char *buf, size_t len, BIGNUM **result)
        return bnsize + 4;
 }
 
-static int read_rsa_bignums(const unsigned char *blob, int blen, RSA **result)
+static int read_public_key(const unsigned char *blob, int blen,
+               struct asymmetric_key *result)
 {
        int ret;
        RSA *rsa;
        BIGNUM *n, *e;
        const unsigned char *p = blob, *end = blob + blen;
 
-       rsa = RSA_new();
-       if (!rsa)
-               return -E_BIGNUM;
+       assert((rsa = RSA_new()));
        ret = read_bignum(p, end - p, &e);
        if (ret < 0)
                goto free_rsa;
@@ -115,7 +125,7 @@ static int read_rsa_bignums(const unsigned char *blob, int blen, RSA **result)
        rsa->n = n;
        rsa->e = e;
 #endif
-       *result = rsa;
+       result->rsa = rsa;
        return 1;
 free_e:
        BN_free(e);
@@ -124,24 +134,109 @@ free_rsa:
        return ret;
 }
 
-static int get_private_key(const char *path, RSA **rsa)
+static int read_pem_private_key(const char *path, struct asymmetric_key *priv)
 {
        EVP_PKEY *pkey;
-       BIO *bio = BIO_new(BIO_s_file());
+       BIO *bio;
 
-       *rsa = NULL;
-       if (!bio)
-               return -E_PRIVATE_KEY;
+       assert((bio = BIO_new(BIO_s_file())));
+       priv->rsa = NULL;
        if (BIO_read_filename(bio, path) <= 0)
                goto bio_free;
        pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
        if (!pkey)
                goto bio_free;
-       *rsa = EVP_PKEY_get1_RSA(pkey);
+       priv->rsa = EVP_PKEY_get1_RSA(pkey);
        EVP_PKEY_free(pkey);
 bio_free:
        BIO_free(bio);
-       return *rsa? RSA_size(*rsa) : -E_PRIVATE_KEY;
+       return priv->rsa? RSA_size(priv->rsa) : -E_PRIVATE_KEY;
+}
+
+static int read_openssh_private_key(const unsigned char *blob,
+               const unsigned char *end, struct asymmetric_key *priv)
+{
+       int ret;
+       RSA *rsa;
+       BIGNUM *n, *e, *d, *iqmp, *p, *q; /* stored in the key file */
+       const unsigned char *cp = blob;
+
+       assert((rsa = RSA_new()));
+       ret = read_bignum(cp, end - cp, &n);
+       if (ret < 0)
+               goto free_rsa;
+       cp += ret;
+       ret = read_bignum(cp, end - cp, &e);
+       if (ret < 0)
+               goto free_n;
+       cp += ret;
+       ret = read_bignum(cp, end - cp, &d);
+       if (ret < 0)
+               goto free_e;
+       cp += ret;
+       ret = read_bignum(cp, end - cp, &iqmp);
+       if (ret < 0)
+               goto free_d;
+       cp += ret;
+       ret = read_bignum(cp, end - cp, &p);
+       if (ret < 0)
+               goto free_iqmp;
+       cp += ret;
+       ret = read_bignum(cp, end - cp, &q);
+       if (ret < 0)
+               goto free_p;
+#ifdef HAVE_RSA_SET0_KEY
+       RSA_set0_key(rsa, n, e, d);
+       RSA_set0_factors(rsa, p, q);
+       RSA_set0_crt_params(rsa, NULL, NULL, iqmp);
+
+#else
+       rsa->n = n;
+       rsa->e = e;
+       rsa->d = d;
+       rsa->iqmp = iqmp;
+       rsa->p = p;
+       rsa->q = q;
+#endif
+       priv->rsa = rsa;
+       return 1;
+free_p:
+       BN_clear_free(p);
+free_iqmp:
+       BN_clear_free(iqmp);
+free_d:
+       BN_clear_free(d);
+free_e:
+       BN_free(e);
+free_n:
+       BN_free(n);
+free_rsa:
+       RSA_free(rsa);
+       return ret;
+}
+
+static int get_private_key(const char *path, struct asymmetric_key *priv)
+{
+       int ret;
+       unsigned char *blob, *end;
+       size_t blob_size;
+
+       priv->rsa = NULL;
+       ret = decode_private_key(path, &blob, &blob_size);
+       if (ret < 0)
+               return ret;
+       end = blob + blob_size;
+       if (ret == PKT_OPENSSH) {
+               ret = find_openssh_bignum_offset(blob, blob_size);
+               if (ret < 0)
+                       goto free_blob;
+               PARA_INFO_LOG("reading RSA params at offset %d\n", ret);
+               ret = read_openssh_private_key(blob + ret, end, priv);
+       } else
+               ret = read_pem_private_key(path, priv);
+free_blob:
+       free(blob);
+       return ret;
 }
 
 int apc_get_pubkey(const char *key_file, struct asymmetric_key **result)
@@ -149,34 +244,34 @@ int apc_get_pubkey(const char *key_file, struct asymmetric_key **result)
        unsigned char *blob;
        size_t decoded_size;
        int ret;
-       struct asymmetric_key *key = para_malloc(sizeof(*key));
+       struct asymmetric_key *pub = alloc(sizeof(*pub));
 
        ret = decode_public_key(key_file, &blob, &decoded_size);
        if (ret < 0)
                goto out;
-       ret = read_rsa_bignums(blob + ret, decoded_size - ret, &key->rsa);
+       ret = read_public_key(blob + ret, decoded_size - ret, pub);
        if (ret < 0)
                goto free_blob;
-       ret = RSA_size(key->rsa);
+       ret = RSA_size(pub->rsa);
        assert(ret > 0);
-       *result = key;
+       *result = pub;
 free_blob:
        free(blob);
 out:
        if (ret < 0) {
-               free(key);
+               free(pub);
                *result = NULL;
                PARA_ERROR_LOG("can not load key %s\n", key_file);
        }
        return ret;
 }
 
-void apc_free_pubkey(struct asymmetric_key *key)
+void apc_free_pubkey(struct asymmetric_key *pub)
 {
-       if (!key)
+       if (!pub)
                return;
-       RSA_free(key->rsa);
-       free(key);
+       RSA_free(pub->rsa);
+       free(pub);
 }
 
 int apc_priv_decrypt(const char *key_file, unsigned char *outbuf,
@@ -190,8 +285,8 @@ int apc_priv_decrypt(const char *key_file, unsigned char *outbuf,
                return ret;
        if (inlen < 0)
                return -E_RSA;
-       priv = para_malloc(sizeof(*priv));
-       ret = get_private_key(key_file, &priv->rsa);
+       priv = alloc(sizeof(*priv));
+       ret = get_private_key(key_file, priv);
        if (ret < 0) {
                free(priv);
                return ret;
@@ -232,10 +327,10 @@ struct stream_cipher {
 
 struct stream_cipher *sc_new(const unsigned char *data, int len)
 {
-       struct stream_cipher *sc = para_malloc(sizeof(*sc));
+       struct stream_cipher *sc = alloc(sizeof(*sc));
 
        assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
-       sc->aes = EVP_CIPHER_CTX_new();
+       assert((sc->aes = EVP_CIPHER_CTX_new()));
        EVP_EncryptInit_ex(sc->aes, EVP_aes_128_ctr(), NULL, data,
                data + AES_CRT128_BLOCK_SIZE);
        return sc;
@@ -256,7 +351,7 @@ static void aes_ctr128_crypt(EVP_CIPHER_CTX *ctx, struct iovec *src,
 
        *dst = (typeof(*dst)) {
                /* Add one for the terminating zero byte. */
-               .iov_base = para_malloc(inlen + 1),
+               .iov_base = alloc(inlen + 1),
                .iov_len = inlen
        };
        ret = EVP_EncryptUpdate(ctx, dst->iov_base, &outlen, src->iov_base, inlen);
@@ -275,8 +370,30 @@ void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
 
 void hash_function(const char *data, unsigned long len, unsigned char *hash)
 {
-       SHA_CTX c;
-       SHA1_Init(&c);
-       SHA1_Update(&c, data, len);
-       SHA1_Final(hash, &c);
+       int ret;
+       EVP_MD_CTX *c;
+
+       assert((c = EVP_MD_CTX_new()));
+       ret = EVP_DigestInit_ex(c, EVP_sha1(), NULL);
+       assert(ret != 0);
+       ret = EVP_DigestUpdate(c, data, len);
+       assert(ret != 0);
+       ret = EVP_DigestFinal_ex(c, hash, NULL);
+       assert(ret != 0);
+       EVP_MD_CTX_free(c);
+}
+
+void hash2_function(const char *data, unsigned long len, unsigned char *hash)
+{
+       int ret;
+       EVP_MD_CTX *c;
+
+       assert((c = EVP_MD_CTX_new()));
+       ret = EVP_DigestInit_ex(c, EVP_sha256(), NULL);
+       assert(ret != 0);
+       ret = EVP_DigestUpdate(c, data, len);
+       assert(ret != 0);
+       ret = EVP_DigestFinal_ex(c, hash, NULL);
+       assert(ret != 0);
+       EVP_MD_CTX_free(c);
 }