X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Flib%2Fcrypto.c;h=af206985dc53493558904b4c873cc89ae105fda8;hb=95c6245affef4000580427d5e0855227dedcd9dc;hp=f3bcbb8fb0109a8c6413e0d56e9c779c129f93ab;hpb=7ae06a3d31025f5db258862c50ddc0974049ca0d;p=bacula%2Fbacula diff --git a/bacula/src/lib/crypto.c b/bacula/src/lib/crypto.c index f3bcbb8fb0..af206985dc 100644 --- a/bacula/src/lib/crypto.c +++ b/bacula/src/lib/crypto.c @@ -19,7 +19,7 @@ * license please contact Landon Fuller . */ /* - Copyright (C) 2005 Kern Sibbald + Copyright (C) 2005-2006 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -176,6 +176,7 @@ ASN1_SEQUENCE(SignatureData) = { ASN1_SEQUENCE(CryptoData) = { ASN1_SIMPLE(CryptoData, version, ASN1_INTEGER), + ASN1_SIMPLE(CryptoData, contentEncryptionAlgorithm, ASN1_OBJECT), ASN1_SIMPLE(CryptoData, iv, ASN1_OCTET_STRING), ASN1_SET_OF(CryptoData, recipientInfo, RecipientInfo) } ASN1_SEQUENCE_END(CryptoData); @@ -269,14 +270,18 @@ struct Signature { SignatureData *sigData; }; -/* Encryption Key Data */ -struct Crypto_Recipients { +/* Encryption Session Data */ +struct Crypto_Session { CryptoData *cryptoData; /* ASN.1 Structure */ - EVP_CIPHER *openssl_cipher; /* OpenSSL Cipher Object */ - unsigned char session_key[EVP_MAX_KEY_LENGTH]; /* Private symmetric session key */ + unsigned char *session_key; /* Private symmetric session key */ size_t session_key_len; /* Symmetric session key length */ }; +/* Symmetric Cipher Context */ +struct Cipher_Context { + EVP_CIPHER_CTX ctx; +}; + /* PEM Password Dispatch Context */ typedef struct PEM_CB_Context { CRYPTO_PEM_PASSWD_CB *pem_callback; @@ -444,6 +449,7 @@ int crypto_keypair_load_cert (X509_KEYPAIR *keypair, const char *file) goto err; } + X509_free(cert); return true; err: @@ -461,6 +467,55 @@ static int crypto_pem_callback_dispatch (char *buf, int size, int rwflag, void * return (ctx->pem_callback(buf, size, ctx->pem_userdata)); } +/* + * Check a PEM-encoded file + * for the existence of a private key. + * Returns: true if a private key is found + * false otherwise + */ +bool crypto_keypair_has_key (const char *file) { + BIO *bio; + char *name = NULL; + char *header = NULL; + unsigned char *data = NULL; + bool retval = false; + long len; + + if (!(bio = BIO_new_file(file, "r"))) { + openssl_post_errors(M_ERROR, _("Unable to open private key file")); + return false; + } + + while (PEM_read_bio(bio, &name, &header, &data, &len)) { + /* We don't care what the data is, just that it's there */ + OPENSSL_free(header); + OPENSSL_free(data); + + /* + * PEM Header Found, check for a private key + * Due to OpenSSL limitations, we must specifically + * list supported PEM private key encodings. + */ + if (strcmp(name, PEM_STRING_RSA) == 0 + || strcmp(name, PEM_STRING_DSA) == 0 + || strcmp(name, PEM_STRING_PKCS8) == 0 + || strcmp(name, PEM_STRING_PKCS8INF) == 0) { + retval = true; + OPENSSL_free(name); + break; + } else { + OPENSSL_free(name); + } + } + + /* Free our bio */ + BIO_free(bio); + + /* Post PEM-decoding error messages, if any */ + openssl_post_errors(M_ERROR, _("Unable to read private key from file")); + return retval; +} + /* * Load a PEM-encoded private key. * Returns: true on success @@ -525,7 +580,7 @@ DIGEST *crypto_digest_new (crypto_digest_t type) DIGEST *digest; const EVP_MD *md = NULL; /* Quell invalid uninitialized warnings */ - digest = (DIGEST *) malloc(sizeof(DIGEST)); + digest = (DIGEST *)malloc(sizeof(DIGEST)); digest->type = type; /* Initialize the OpenSSL message digest context */ @@ -571,7 +626,8 @@ err: * Returns: true on success * false on failure */ -bool crypto_digest_update (DIGEST *digest, const void *data, size_t length) { +bool crypto_digest_update(DIGEST *digest, const uint8_t *data, uint32_t length) +{ if (EVP_DigestUpdate(&digest->ctx, data, length) == 0) { return true; } else { @@ -586,8 +642,8 @@ bool crypto_digest_update (DIGEST *digest, const void *data, size_t length) { * Returns: true on success * false on failure */ -bool crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) { - if (!EVP_DigestFinal(&digest->ctx, (unsigned char *) dest, length)) { +bool crypto_digest_finalize (DIGEST *digest, uint8_t *dest, uint32_t *length) { + if (!EVP_DigestFinal(&digest->ctx, dest, (unsigned int *)length)) { return false; } else { return true; @@ -819,14 +875,14 @@ err: * Returns: true on success, stores the encoded data in dest, and the size in length. * false on failure. */ -int crypto_sign_encode(SIGNATURE *sig, void *dest, size_t *length) +int crypto_sign_encode(SIGNATURE *sig, uint8_t *dest, uint32_t *length) { if (*length == 0) { *length = i2d_SignatureData(sig->sigData, NULL); return true; } - *length = i2d_SignatureData(sig->sigData, (unsigned char **) &dest); + *length = i2d_SignatureData(sig->sigData, (unsigned char **)&dest); return true; } @@ -839,16 +895,16 @@ int crypto_sign_encode(SIGNATURE *sig, void *dest, size_t *length) */ -SIGNATURE *crypto_sign_decode(const void *sigData, size_t length) +SIGNATURE *crypto_sign_decode(const uint8_t *sigData, uint32_t length) { SIGNATURE *sig; #if (OPENSSL_VERSION_NUMBER >= 0x0090800FL) const unsigned char *p = (const unsigned char *) sigData; #else - unsigned char *p = (unsigned char *) sigData; + unsigned char *p = (unsigned char *)sigData; #endif - sig = (SIGNATURE *) malloc(sizeof(SIGNATURE)); + sig = (SIGNATURE *)malloc(sizeof(SIGNATURE)); if (!sig) { return NULL; } @@ -859,6 +915,7 @@ SIGNATURE *crypto_sign_decode(const void *sigData, size_t length) if (!sig->sigData) { /* Allocation / Decoding failed in OpenSSL */ openssl_post_errors(M_ERROR, _("Signature decoding failed")); + free(sig); return NULL; } @@ -875,34 +932,38 @@ void crypto_sign_free(SIGNATURE *sig) } /* - * Create a new encryption recipient. - * Returns: A pointer to a CRYPTO_RECIPIENTS object on success. + * Create a new encryption session. + * Returns: A pointer to a CRYPTO_SESSION object on success. * NULL on failure. */ -CRYPTO_RECIPIENTS *crypto_recipients_new (crypto_cipher_t cipher, alist *pubkeys) +CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys) { - CRYPTO_RECIPIENTS *cr; + CRYPTO_SESSION *cs; X509_KEYPAIR *keypair; const EVP_CIPHER *ec; unsigned char *iv; int iv_len; - /* Allocate our recipient description structures */ - cr = (CRYPTO_RECIPIENTS *) malloc(sizeof(CRYPTO_RECIPIENTS)); - if (!cr) { + /* Allocate our session description structures */ + cs = (CRYPTO_SESSION *) malloc(sizeof(CRYPTO_SESSION)); + if (!cs) { return NULL; } - cr->cryptoData = CryptoData_new(); + /* Initialize required fields */ + cs->session_key = NULL; + + /* Allocate a CryptoData structure */ + cs->cryptoData = CryptoData_new(); - if (!cr->cryptoData) { + if (!cs->cryptoData) { /* Allocation failed in OpenSSL */ - free(cr); + free(cs); return NULL; } /* Set the ASN.1 structure version number */ - ASN1_INTEGER_set(cr->cryptoData->version, BACULA_ASN1_VERSION); + ASN1_INTEGER_set(cs->cryptoData->version, BACULA_ASN1_VERSION); /* * Acquire a cipher instance and set the ASN.1 cipher NID @@ -910,35 +971,36 @@ CRYPTO_RECIPIENTS *crypto_recipients_new (crypto_cipher_t cipher, alist *pubkeys switch (cipher) { case CRYPTO_CIPHER_AES_128_CBC: /* AES 128 bit CBC */ - cr->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_128_cbc); + cs->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_128_cbc); ec = EVP_aes_128_cbc(); break; case CRYPTO_CIPHER_AES_192_CBC: /* AES 192 bit CBC */ - cr->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_192_cbc); + cs->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_192_cbc); ec = EVP_aes_192_cbc(); break; case CRYPTO_CIPHER_AES_256_CBC: /* AES 256 bit CBC */ - cr->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_256_cbc); + cs->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_256_cbc); ec = EVP_aes_256_cbc(); break; case CRYPTO_CIPHER_BLOWFISH_CBC: /* Blowfish CBC */ - cr->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_bf_cbc); + cs->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_bf_cbc); ec = EVP_bf_cbc(); break; default: Emsg0(M_ERROR, 0, _("Unsupported cipher type specified\n")); - crypto_recipients_free(cr); + crypto_session_free(cs); return NULL; } /* Generate a symmetric session key */ - cr->session_key_len = EVP_CIPHER_key_length(ec); - if (RAND_bytes(cr->session_key, cr->session_key_len) <= 0) { + cs->session_key_len = EVP_CIPHER_key_length(ec); + cs->session_key = (unsigned char *) malloc(cs->session_key_len); + if (RAND_bytes(cs->session_key, cs->session_key_len) <= 0) { /* OpenSSL failure */ - crypto_recipients_free(cr); + crypto_session_free(cs); return NULL; } @@ -947,23 +1009,26 @@ CRYPTO_RECIPIENTS *crypto_recipients_new (crypto_cipher_t cipher, alist *pubkeys iv = (unsigned char *) malloc(iv_len); if (!iv) { /* Malloc failure */ - crypto_recipients_free(cr); + crypto_session_free(cs); return NULL; } /* Generate random IV */ if (RAND_bytes(iv, iv_len) <= 0) { /* OpenSSL failure */ - crypto_recipients_free(cr); + crypto_session_free(cs); + free(iv); return NULL; } /* Store it in our ASN.1 structure */ - if (!M_ASN1_OCTET_STRING_set(cr->cryptoData->iv, iv, iv_len)) { + if (!M_ASN1_OCTET_STRING_set(cs->cryptoData->iv, iv, iv_len)) { /* Allocation failed in OpenSSL */ - crypto_recipients_free(cr); + crypto_session_free(cs); + free(iv); return NULL; } + free(iv); } /* @@ -978,7 +1043,7 @@ CRYPTO_RECIPIENTS *crypto_recipients_new (crypto_cipher_t cipher, alist *pubkeys ri = RecipientInfo_new(); if (!ri) { /* Allocation failed in OpenSSL */ - crypto_recipients_free(cr); + crypto_session_free(cs); return NULL; } @@ -997,14 +1062,14 @@ CRYPTO_RECIPIENTS *crypto_recipients_new (crypto_cipher_t cipher, alist *pubkeys ekey = (unsigned char *) malloc(EVP_PKEY_size(keypair->pubkey)); if (!ekey) { RecipientInfo_free(ri); - crypto_recipients_free(cr); + crypto_session_free(cs); return NULL; } - if ((ekey_len = EVP_PKEY_encrypt(ekey, cr->session_key, cr->session_key_len, keypair->pubkey)) <= 0) { + if ((ekey_len = EVP_PKEY_encrypt(ekey, cs->session_key, cs->session_key_len, keypair->pubkey)) <= 0) { /* OpenSSL failure */ RecipientInfo_free(ri); - crypto_recipients_free(cr); + crypto_session_free(cs); free(ekey); return NULL; } @@ -1013,7 +1078,7 @@ CRYPTO_RECIPIENTS *crypto_recipients_new (crypto_cipher_t cipher, alist *pubkeys if (!M_ASN1_OCTET_STRING_set(ri->encryptedKey, ekey, ekey_len)) { /* Allocation failed in OpenSSL */ RecipientInfo_free(ri); - crypto_recipients_free(cr); + crypto_session_free(cs); free(ekey); return NULL; } @@ -1022,21 +1087,260 @@ CRYPTO_RECIPIENTS *crypto_recipients_new (crypto_cipher_t cipher, alist *pubkeys free(ekey); /* Push the new RecipientInfo structure onto the stack */ - sk_RecipientInfo_push(cr->cryptoData->recipientInfo, ri); + sk_RecipientInfo_push(cs->cryptoData->recipientInfo, ri); + } + + return cs; +} + +/* + * Encodes the CryptoData structure. The length argument is used to specify the + * size of dest. A length of 0 will cause no data to be written to dest, and the + * required length to be written to length. The caller can then allocate sufficient + * space for the output. + * + * Returns: true on success, stores the encoded data in dest, and the size in length. + * false on failure. + */ +bool crypto_session_encode(CRYPTO_SESSION *cs, uint8_t *dest, uint32_t *length) +{ + if (*length == 0) { + *length = i2d_CryptoData(cs->cryptoData, NULL); + return true; + } + + *length = i2d_CryptoData(cs->cryptoData, &dest); + return true; +} + +/* + * Decodes the CryptoData structure. The length argument is + * used to specify the size of data. + * + * Returns: CRYPTO_SESSION instance on success. + * NULL on failure. + * Returns: CRYPTO_ERROR_NONE and a pointer to a newly allocated CRYPTO_SESSION structure in *session on success. + * A crypto_error_t value on failure. + */ +crypto_error_t crypto_session_decode(const uint8_t *data, uint32_t length, alist *keypairs, CRYPTO_SESSION **session) +{ + CRYPTO_SESSION *cs; + X509_KEYPAIR *keypair; + STACK_OF(RecipientInfo) *recipients; + crypto_error_t retval = CRYPTO_ERROR_NONE; +#if (OPENSSL_VERSION_NUMBER >= 0x0090800FL) + const unsigned char *p = (const unsigned char *)data; +#else + unsigned char *p = (unsigned char *)data; +#endif + + /* bacula-fd.conf doesn't contains any key */ + if (!keypairs) { + return CRYPTO_ERROR_NORECIPIENT; + } + + cs = (CRYPTO_SESSION *) malloc(sizeof(CRYPTO_SESSION)); + if (!cs) { + return CRYPTO_ERROR_INTERNAL; + } + + /* Initialize required fields */ + cs->session_key = NULL; + + /* d2i_CryptoData modifies the supplied pointer */ + cs->cryptoData = d2i_CryptoData(NULL, &p, length); + + if (!cs->cryptoData) { + /* Allocation / Decoding failed in OpenSSL */ + openssl_post_errors(M_ERROR, _("CryptoData decoding failed")); + retval = CRYPTO_ERROR_INTERNAL; + goto err; + } + + recipients = cs->cryptoData->recipientInfo; + + /* + * Find a matching RecipientInfo structure for a supplied + * public key + */ + foreach_alist(keypair, keypairs) { + RecipientInfo *ri; + int i; + + /* Private key available? */ + if (keypair->privkey == NULL) { + continue; + } + + for (i = 0; i < sk_RecipientInfo_num(recipients); i++) { + ri = sk_RecipientInfo_value(recipients, i); + + /* Match against the subjectKeyIdentifier */ + if (M_ASN1_OCTET_STRING_cmp(keypair->keyid, ri->subjectKeyIdentifier) == 0) { + /* Match found, extract symmetric encryption session data */ + + /* RSA is required. */ + assert(EVP_PKEY_type(keypair->privkey->type) == EVP_PKEY_RSA); + + /* If we recieve a RecipientInfo structure that does not use + * RSA, return an error */ + if (OBJ_obj2nid(ri->keyEncryptionAlgorithm) != NID_rsaEncryption) { + retval = CRYPTO_ERROR_INVALID_CRYPTO; + goto err; + } + + /* Decrypt the session key */ + /* Allocate sufficient space for the largest possible decrypted data */ + cs->session_key = (unsigned char *) malloc(EVP_PKEY_size(keypair->privkey)); + cs->session_key_len = EVP_PKEY_decrypt(cs->session_key, M_ASN1_STRING_data(ri->encryptedKey), + M_ASN1_STRING_length(ri->encryptedKey), keypair->privkey); + + if (cs->session_key_len <= 0) { + openssl_post_errors(M_ERROR, _("Failure decrypting the session key")); + retval = CRYPTO_ERROR_DECRYPTION; + goto err; + } + + /* Session key successfully extracted, return the CRYPTO_SESSION structure */ + *session = cs; + return CRYPTO_ERROR_NONE; + } + } + } + + /* No matching recipient found */ + return CRYPTO_ERROR_NORECIPIENT; + +err: + crypto_session_free(cs); + return retval; +} + +/* + * Free memory associated with a crypto session object. + */ +void crypto_session_free (CRYPTO_SESSION *cs) +{ + if (cs->cryptoData) { + CryptoData_free(cs->cryptoData); + } + if (cs->session_key){ + free(cs->session_key); + } + free(cs); +} + +/* + * Create a new crypto cipher context with the specified session object + * Returns: A pointer to a CIPHER_CONTEXT object on success. The cipher block size is returned in blocksize. + * NULL on failure. + */ +CIPHER_CONTEXT *crypto_cipher_new (CRYPTO_SESSION *cs, bool encrypt, uint32_t *blocksize) +{ + CIPHER_CONTEXT *cipher_ctx; + const EVP_CIPHER *ec; + + cipher_ctx = (CIPHER_CONTEXT *) malloc(sizeof(CIPHER_CONTEXT)); + if (!cipher_ctx) { + return NULL; + } + + /* + * Acquire a cipher instance for the given ASN.1 cipher NID + */ + if ((ec = EVP_get_cipherbyobj(cs->cryptoData->contentEncryptionAlgorithm)) == NULL) { + Emsg1(M_ERROR, 0, _("Unsupported contentEncryptionAlgorithm: %d\n"), OBJ_obj2nid(cs->cryptoData->contentEncryptionAlgorithm)); + free(cipher_ctx); + return NULL; + } + + /* Initialize the OpenSSL cipher context */ + EVP_CIPHER_CTX_init(&cipher_ctx->ctx); + if (encrypt) { + /* Initialize for encryption */ + if (!EVP_CipherInit_ex(&cipher_ctx->ctx, ec, NULL, NULL, NULL, 1)) { + openssl_post_errors(M_ERROR, _("OpenSSL cipher context initialization failed")); + goto err; + } + } else { + /* Initialize for decryption */ + if (!EVP_CipherInit_ex(&cipher_ctx->ctx, ec, NULL, NULL, NULL, 0)) { + openssl_post_errors(M_ERROR, _("OpenSSL cipher context initialization failed")); + goto err; + } + } + + /* Set the key size */ + if (!EVP_CIPHER_CTX_set_key_length(&cipher_ctx->ctx, cs->session_key_len)) { + openssl_post_errors(M_ERROR, _("Encryption session provided an invalid symmetric key")); + goto err; + } + + /* Validate the IV length */ + if (EVP_CIPHER_iv_length(ec) != M_ASN1_STRING_length(cs->cryptoData->iv)) { + openssl_post_errors(M_ERROR, _("Encryption session provided an invalid IV")); + goto err; } + + /* Add the key and IV to the cipher context */ + if (!EVP_CipherInit_ex(&cipher_ctx->ctx, NULL, NULL, cs->session_key, M_ASN1_STRING_data(cs->cryptoData->iv), -1)) { + openssl_post_errors(M_ERROR, _("OpenSSL cipher context key/IV initialization failed")); + goto err; + } + + *blocksize = EVP_CIPHER_CTX_block_size(&cipher_ctx->ctx); + return cipher_ctx; - return cr; +err: + crypto_cipher_free(cipher_ctx); + return NULL; } + /* - * Free memory associated with a crypto recipient object. + * Encrypt/Decrypt length bytes of data using the provided cipher context + * Returns: true on success, number of bytes output in written + * false on failure */ -void crypto_recipients_free (CRYPTO_RECIPIENTS *cr) +bool crypto_cipher_update(CIPHER_CONTEXT *cipher_ctx, const uint8_t *data, uint32_t length, const uint8_t *dest, uint32_t *written) { - CryptoData_free(cr->cryptoData); - free(cr); + if (!EVP_CipherUpdate(&cipher_ctx->ctx, (unsigned char *)dest, (int *)written, (const unsigned char *)data, length)) { + /* This really shouldn't fail */ + return false; + } else { + return true; + } } +/* + * Finalize the cipher context, writing any remaining data and necessary padding + * to dest, and the size in written. + * The result size will either be one block of data or zero. + * + * Returns: true on success + * false on failure + */ +bool crypto_cipher_finalize (CIPHER_CONTEXT *cipher_ctx, uint8_t *dest, uint32_t *written) +{ + if (!EVP_CipherFinal_ex(&cipher_ctx->ctx, (unsigned char *)dest, (int *) written)) { + /* This really shouldn't fail */ + return false; + } else { + return true; + } +} + + +/* + * Free memory associated with a cipher context. + */ +void crypto_cipher_free (CIPHER_CONTEXT *cipher_ctx) +{ + EVP_CIPHER_CTX_cleanup(&cipher_ctx->ctx); + free (cipher_ctx); +} + + /* * Perform global initialization of OpenSSL * This function is not thread safe. @@ -1054,9 +1358,12 @@ int init_crypto (void) /* Load libssl and libcrypto human-readable error strings */ SSL_load_error_strings(); - /* Register OpenSSL ciphers */ + /* Initialize OpenSSL SSL library */ SSL_library_init(); + /* Register OpenSSL ciphers and digests */ + OpenSSL_add_all_algorithms(); + if (!openssl_seed_prng()) { Emsg0(M_ERROR_TERM, 0, _("Failed to seed OpenSSL PRNG\n")); } @@ -1092,6 +1399,9 @@ int cleanup_crypto (void) /* Free libssl and libcrypto error strings */ ERR_free_strings(); + /* Free all ciphers and digests */ + EVP_cleanup(); + /* Free memory used by PRNG */ RAND_cleanup(); @@ -1128,7 +1438,7 @@ DIGEST *crypto_digest_new (crypto_digest_t type) { DIGEST *digest; - digest = (DIGEST *) malloc(sizeof(DIGEST)); + digest = (DIGEST *)malloc(sizeof(DIGEST)); digest->type = type; switch (type) { @@ -1147,7 +1457,8 @@ DIGEST *crypto_digest_new (crypto_digest_t type) return (digest); } -bool crypto_digest_update (DIGEST *digest, const void *data, size_t length) { +bool crypto_digest_update(DIGEST *digest, const uint8_t *data, uint32_t length) +{ switch (digest->type) { case CRYPTO_DIGEST_MD5: /* Doesn't return anything ... */ @@ -1167,8 +1478,8 @@ bool crypto_digest_update (DIGEST *digest, const void *data, size_t length) { } } -bool crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) { - +bool crypto_digest_finalize(DIGEST *digest, uint8_t *dest, uint32_t *length) +{ switch (digest->type) { case CRYPTO_DIGEST_MD5: /* Guard against programmer error by either the API client or @@ -1176,7 +1487,7 @@ bool crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) { assert(*length >= CRYPTO_DIGEST_MD5_SIZE); *length = CRYPTO_DIGEST_MD5_SIZE; /* Doesn't return anything ... */ - MD5Final((unsigned char *) dest, &digest->md5); + MD5Final((unsigned char *)dest, &digest->md5); return true; case CRYPTO_DIGEST_SHA1: /* Guard against programmer error by either the API client or @@ -1196,7 +1507,7 @@ bool crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) { return false; } -void crypto_digest_free (DIGEST *digest) +void crypto_digest_free(DIGEST *digest) { free (digest); } @@ -1211,20 +1522,28 @@ crypto_error_t crypto_sign_get_digest (SIGNATURE *sig, X509_KEYPAIR *keypair, DI crypto_error_t crypto_sign_verify (SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST *digest) { return CRYPTO_ERROR_INTERNAL; } int crypto_sign_add_signer (SIGNATURE *sig, DIGEST *digest, X509_KEYPAIR *keypair) { return false; } -int crypto_sign_encode (SIGNATURE *sig, void *dest, size_t *length) { return false; } +int crypto_sign_encode (SIGNATURE *sig, uint8_t *dest, uint32_t *length) { return false; } -SIGNATURE *crypto_sign_decode (const void *sigData, size_t length) { return false; } +SIGNATURE *crypto_sign_decode (const uint8_t *sigData, uint32_t length) { return NULL; } void crypto_sign_free (SIGNATURE *sig) { } X509_KEYPAIR *crypto_keypair_new (void) { return NULL; } X509_KEYPAIR *crypto_keypair_dup (X509_KEYPAIR *keypair) { return NULL; } int crypto_keypair_load_cert (X509_KEYPAIR *keypair, const char *file) { return false; } +bool crypto_keypair_has_key (const char *file) { return false; } int crypto_keypair_load_key (X509_KEYPAIR *keypair, const char *file, CRYPTO_PEM_PASSWD_CB *pem_callback, const void *pem_userdata) { return false; } void crypto_keypair_free (X509_KEYPAIR *keypair) { } -CRYPTO_RECIPIENTS *crypto_recipients_new (crypto_cipher_t cipher, alist *pubkeys) { return NULL; } -void crypto_recipients_free (CRYPTO_RECIPIENTS *cr) { } +CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys) { return NULL; } +void crypto_session_free (CRYPTO_SESSION *cs) { } +bool crypto_session_encode (CRYPTO_SESSION *cs, uint8_t *dest, uint32_t *length) { return false; } +crypto_error_t crypto_session_decode(const uint8_t *data, uint32_t length, alist *keypairs, CRYPTO_SESSION **session) { return CRYPTO_ERROR_INTERNAL; } + +CIPHER_CONTEXT *crypto_cipher_new (CRYPTO_SESSION *cs, bool encrypt, uint32_t *blocksize) { return NULL; } +bool crypto_cipher_update (CIPHER_CONTEXT *cipher_ctx, const uint8_t *data, uint32_t length, const uint8_t *dest, uint32_t *written) { return false; } +bool crypto_cipher_finalize (CIPHER_CONTEXT *cipher_ctx, uint8_t *dest, uint32_t *written) { return false; } +void crypto_cipher_free (CIPHER_CONTEXT *cipher_ctx) { } #endif /* HAVE_CRYPTO */ @@ -1291,10 +1610,16 @@ const char *crypto_strerror(crypto_error_t error) { return "No error"; case CRYPTO_ERROR_NOSIGNER: return "Signer not found"; + case CRYPTO_ERROR_NORECIPIENT: + return "Recipient not found"; case CRYPTO_ERROR_INVALID_DIGEST: return "Unsupported digest algorithm"; + case CRYPTO_ERROR_INVALID_CRYPTO: + return "Unsupported encryption algorithm"; case CRYPTO_ERROR_BAD_SIGNATURE: return "Signature is invalid"; + case CRYPTO_ERROR_DECRYPTION: + return "Decryption error"; case CRYPTO_ERROR_INTERNAL: /* This shouldn't happen */ return "Internal error";