Adapt to OpenSSL 1.1.0
[libisds.git] / src / crypto_openssl.c
blob1485f696128266b29a9cf29544043b00bcc8c487
2 #include <assert.h>
3 #include <locale.h>
4 #include <openssl/bio.h>
5 #include <openssl/cms.h>
6 #include <openssl/crypto.h>
7 #include <openssl/err.h>
8 #include <openssl/evp.h>
9 #include <openssl/pkcs7.h>
10 #include <openssl/x509.h>
12 #include "isds_priv.h"
13 #include "utils.h"
16 #ifndef SHA1_DIGEST_LENGTH
17 # define SHA1_DIGEST_LENGTH 20
18 #endif /* !SHA1_DIGEST_LENGTH */
20 #if OPENSSL_VERSION_NUMBER < 0x10100000L
21 static EVP_MD_CTX *EVP_MD_CTX_new(void) {
22 EVP_MD_CTX *mdctx = malloc(sizeof(*mdctx));
23 if (NULL != mdctx) {
24 EVP_MD_CTX_init(mdctx);
26 return mdctx;
29 static void EVP_MD_CTX_free(EVP_MD_CTX *mdctx) {
30 EVP_MD_CTX_cleanup(mdctx);
31 free(mdctx);
33 #endif
35 /* Initialise all cryptographic libraries which libisds depends on.
36 * @return IE_SUCCESS if everything went all-right. */
37 _hidden isds_error _isds_init_crypto(void)
39 OpenSSL_add_all_digests(); /* Loads all digest algorithms. */
41 ERR_load_crypto_strings();
42 //ERR_load_CMS_strings();
44 version_openssl = SSLeay_version(SSLEAY_VERSION);
46 return IE_SUCCESS;
49 /* Computes hash from @input with @length and store it into @hash.
50 * The hash algorithm is defined inside @hash.
51 * @input is input block to hash
52 * @length is @input block length in bytes
53 * @hash input algorithm, output hash value and hash length; hash value will be
54 * reallocated, it's always valid pointer or NULL (before and after call) */
55 _hidden isds_error _isds_compute_hash(const void *input,
56 const size_t length, struct isds_hash *hash)
58 isds_error retval = IE_SUCCESS;
59 void *hash_buf = NULL;
60 size_t hash_len = 0;
61 EVP_MD_CTX *mdctx = NULL;
62 const char *hash_name = NULL;
63 const EVP_MD *md;
64 unsigned int md_len;
66 if (((0 != length) && (NULL == input)) || (NULL == hash)) {
67 return IE_INVAL;
70 isds_log(ILF_SEC, ILL_DEBUG,
71 _("Data hash requested, length=%zu, content:\n%*s\n"
72 "End of data to hash\n"), length, length, input);
74 /* Select algorithm */
75 switch (hash->algorithm) {
76 case HASH_ALGORITHM_MD5: hash_name = "MD5"; break;
77 case HASH_ALGORITHM_SHA_1: hash_name = "SHA1"; break;
78 case HASH_ALGORITHM_SHA_224: hash_name = "SHA224"; break;
79 case HASH_ALGORITHM_SHA_256: hash_name = "SHA256"; break;
80 case HASH_ALGORITHM_SHA_384: hash_name = "SHA384"; break;
81 case HASH_ALGORITHM_SHA_512: hash_name = "SHA512"; break;
82 default:
83 retval = IE_NOTSUP;
84 goto fail;
87 md = EVP_get_digestbyname(hash_name);
88 if (NULL == md) {
89 retval = IE_NOTSUP;
90 goto fail;
93 mdctx = EVP_MD_CTX_new();
94 if (NULL == mdctx) {
95 retval = IE_NOMEM;
96 goto fail;
98 if (!EVP_DigestInit(mdctx, md)) {
99 retval = IE_ERROR;
100 goto fail;
102 if (!EVP_DigestUpdate(mdctx, input, length)) {
103 retval = IE_ERROR;
104 goto fail;
107 hash_len = EVP_MD_size(md);
108 hash_buf = realloc(hash->value, hash_len);
109 if (NULL == hash_buf) {
110 retval = IE_NOMEM;
111 goto fail;
113 hash->value = hash_buf;
114 hash->length = hash_len;
116 if (!EVP_DigestFinal_ex(mdctx, hash->value, &md_len)) {
117 retval = IE_ERROR;
118 goto fail;
121 EVP_MD_CTX_free(mdctx);
122 mdctx = NULL;
124 return IE_SUCCESS;
126 fail:
127 if (NULL != mdctx) {
128 EVP_MD_CTX_free(mdctx);
130 return retval;
133 /* Free CMS data buffer allocated inside _isds_extract_cms_data().
134 * This is necessary because GPGME.
135 * @buffer is pointer to memory to free */
136 _hidden void _isds_cms_data_free(void *buffer)
138 free(buffer);
141 /* Extract data from CMS (successor of PKCS#7)
142 * The CMS' signature is is not verified.
143 * @context is session context
144 * @cms is input block with CMS structure
145 * @cms_length is @cms block length in bytes
146 * @data are automatically reallocated bit stream with data found in @cms
147 * You must free them with _isds_cms_data_free().
148 * @data_length is length of @data in bytes */
149 _hidden isds_error _isds_extract_cms_data(struct isds_ctx *context,
150 const void *cms, const size_t cms_length,
151 void **data, size_t *data_length)
153 unsigned long err;
154 isds_error retval = IE_SUCCESS;
155 BIO *bio = NULL;
156 CMS_ContentInfo *cms_ci = NULL;
157 const ASN1_OBJECT *asn1_obj;
158 ASN1_OCTET_STRING **pos;
159 int nid;
160 char *locale_str;
162 assert(NULL != context);
164 if ((NULL == cms) || (0 == cms_length) ||
165 (NULL == data) || (NULL == data_length)) {
166 return IE_INVAL;
169 zfree(*data);
170 *data_length = 0;
172 bio = BIO_new_mem_buf((void *) cms, cms_length);
173 if (NULL == bio) {
174 isds_log_message(context, _("Creating CMS reader BIO failed"));
175 while (0 != (err = ERR_get_error())) {
176 locale_str = _isds_utf82locale(ERR_error_string(err, NULL));
177 if (NULL != locale_str) {
178 isds_log_message(context, locale_str);
179 free(locale_str);
182 retval = IE_ERROR;
183 goto fail;
186 cms_ci = d2i_CMS_bio(bio, NULL);
187 if (NULL == cms_ci) {
188 isds_log_message(context, _("Cannot parse CMS"));
189 while (0 != (err = ERR_get_error())) {
190 locale_str = _isds_utf82locale(ERR_error_string(err, NULL));
191 if (NULL != locale_str) {
192 isds_log_message(context, locale_str);
193 free(locale_str);
196 retval = IE_ERROR;
197 goto fail;
200 BIO_free(bio); bio = NULL;
202 asn1_obj = CMS_get0_type(cms_ci);
203 nid = OBJ_obj2nid(asn1_obj);
204 switch (nid) {
205 case NID_pkcs7_data:
206 case NID_id_smime_ct_compressedData:
207 case NID_id_smime_ct_authData:
208 case NID_pkcs7_enveloped:
209 case NID_pkcs7_encrypted:
210 case NID_pkcs7_digest:
211 assert(0);
212 retval = IE_ERROR;
213 goto fail;
214 break;
215 case NID_pkcs7_signed:
216 break;
217 default:
218 assert(0);
219 retval = IE_ERROR;
220 goto fail;
221 break;
224 pos = CMS_get0_content(cms_ci);
225 if ((NULL == pos) || (NULL == *pos)) {
226 assert(0);
227 retval = IE_ERROR;
228 goto fail;
231 *data = malloc((*pos)->length);
232 if (NULL == *data) {
233 retval = IE_NOMEM;
234 goto fail;
236 *data_length = (*pos)->length;
237 memcpy(*data, (*pos)->data, (*pos)->length);
239 CMS_ContentInfo_free(cms_ci); cms_ci = NULL;
241 return IE_SUCCESS;
243 fail:
244 if (NULL != bio) {
245 BIO_free(bio);
247 if (NULL != cms_ci) {
248 CMS_ContentInfo_free(cms_ci);
250 return retval;