Do not use dolar in formatting strings
[libisds.git] / src / crypto_openssl.c
blob40e89cb425fe13f430b3ce200a1e0231a4191c5c
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 */
21 /* Initialise all cryptographic libraries which libisds depends on.
22 * @return IE_SUCCESS if everything went all-right. */
23 _hidden isds_error _isds_init_crypto(void)
25 OpenSSL_add_all_digests(); /* Loads all digest algorithms. */
27 ERR_load_crypto_strings();
28 //ERR_load_CMS_strings();
30 version_openssl = SSLeay_version(SSLEAY_VERSION);
32 return IE_SUCCESS;
35 /* Computes hash from @input with @length and store it into @hash.
36 * The hash algorithm is defined inside @hash.
37 * @input is input block to hash
38 * @length is @input block length in bytes
39 * @hash input algorithm, output hash value and hash length; hash value will be
40 * reallocated, it's always valid pointer or NULL (before and after call) */
41 _hidden isds_error _isds_compute_hash(const void *input,
42 const size_t length, struct isds_hash *hash)
44 isds_error retval = IE_SUCCESS;
45 void *hash_buf = NULL;
46 size_t hash_len = 0;
47 EVP_MD_CTX *mdctx = NULL;
48 const char *hash_name = NULL;
49 const EVP_MD *md;
50 unsigned int md_len;
52 if (((0 != length) && (NULL == input)) || (NULL == hash)) {
53 return IE_INVAL;
56 isds_log(ILF_SEC, ILL_DEBUG,
57 _("Data hash requested, length=%zu, content:\n%*s\n"
58 "End of data to hash\n"), length, length, input);
60 /* Select algorithm */
61 switch (hash->algorithm) {
62 case HASH_ALGORITHM_MD5: hash_name = "MD5"; break;
63 case HASH_ALGORITHM_SHA_1: hash_name = "SHA1"; break;
64 case HASH_ALGORITHM_SHA_224: hash_name = "SHA224"; break;
65 case HASH_ALGORITHM_SHA_256: hash_name = "SHA256"; break;
66 case HASH_ALGORITHM_SHA_384: hash_name = "SHA384"; break;
67 case HASH_ALGORITHM_SHA_512: hash_name = "SHA512"; break;
68 default:
69 retval = IE_NOTSUP;
70 goto fail;
73 md = EVP_get_digestbyname(hash_name);
74 if (NULL == md) {
75 retval = IE_NOTSUP;
76 goto fail;
79 mdctx = malloc(sizeof(*mdctx));
80 if (NULL == mdctx) {
81 retval = IE_NOMEM;
82 goto fail;
84 EVP_MD_CTX_init(mdctx);
85 if (!EVP_DigestInit(mdctx, md)) {
86 retval = IE_ERROR;
87 goto fail;
89 if (!EVP_DigestUpdate(mdctx, input, length)) {
90 retval = IE_ERROR;
91 goto fail;
94 hash_len = EVP_MD_size(md);
95 hash_buf = realloc(hash->value, hash_len);
96 if (NULL == hash_buf) {
97 retval = IE_NOMEM;
98 goto fail;
100 hash->value = hash_buf;
101 hash->length = hash_len;
103 if (!EVP_DigestFinal_ex(mdctx, hash->value, &md_len)) {
104 retval = IE_ERROR;
105 goto fail;
108 EVP_MD_CTX_cleanup(mdctx); free(mdctx); mdctx = NULL;
110 return IE_SUCCESS;
112 fail:
113 if (NULL != mdctx) {
114 EVP_MD_CTX_cleanup(mdctx); free(mdctx);
116 return retval;
119 /* Free CMS data buffer allocated inside _isds_extract_cms_data().
120 * This is necessary because GPGME.
121 * @buffer is pointer to memory to free */
122 _hidden void _isds_cms_data_free(void *buffer)
124 free(buffer);
127 /* Extract data from CMS (successor of PKCS#7)
128 * The CMS' signature is is not verified.
129 * @context is session context
130 * @cms is input block with CMS structure
131 * @cms_length is @cms block length in bytes
132 * @data are automatically reallocated bit stream with data found in @cms
133 * You must free them with _isds_cms_data_free().
134 * @data_length is length of @data in bytes */
135 _hidden isds_error _isds_extract_cms_data(struct isds_ctx *context,
136 const void *cms, const size_t cms_length,
137 void **data, size_t *data_length)
139 unsigned long err;
140 isds_error retval = IE_SUCCESS;
141 BIO *bio = NULL;
142 CMS_ContentInfo *cms_ci = NULL;
143 const ASN1_OBJECT *asn1_obj;
144 ASN1_OCTET_STRING **pos;
145 int nid;
146 char *locale_str;
148 assert(NULL != context);
150 if ((NULL == cms) || (0 == cms_length) ||
151 (NULL == data) || (NULL == data_length)) {
152 return IE_INVAL;
155 zfree(*data);
156 *data_length = 0;
158 bio = BIO_new_mem_buf((void *) cms, cms_length);
159 if (NULL == bio) {
160 isds_log_message(context, _("Creating CMS reader BIO failed"));
161 while (0 != (err = ERR_get_error())) {
162 locale_str = _isds_utf82locale(ERR_error_string(err, NULL));
163 if (NULL != locale_str) {
164 isds_log_message(context, locale_str);
165 free(locale_str);
168 retval = IE_ERROR;
169 goto fail;
172 cms_ci = d2i_CMS_bio(bio, NULL);
173 if (NULL == cms_ci) {
174 isds_log_message(context, _("Cannot parse CMS"));
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 BIO_free(bio); bio = NULL;
188 asn1_obj = CMS_get0_type(cms_ci);
189 nid = OBJ_obj2nid(asn1_obj);
190 switch (nid) {
191 case NID_pkcs7_data:
192 case NID_id_smime_ct_compressedData:
193 case NID_id_smime_ct_authData:
194 case NID_pkcs7_enveloped:
195 case NID_pkcs7_encrypted:
196 case NID_pkcs7_digest:
197 assert(0);
198 retval = IE_ERROR;
199 goto fail;
200 break;
201 case NID_pkcs7_signed:
202 break;
203 default:
204 assert(0);
205 retval = IE_ERROR;
206 goto fail;
207 break;
210 pos = CMS_get0_content(cms_ci);
211 if ((NULL == pos) || (NULL == *pos)) {
212 assert(0);
213 retval = IE_ERROR;
214 goto fail;
217 *data = malloc((*pos)->length);
218 if (NULL == *data) {
219 retval = IE_NOMEM;
220 goto fail;
222 *data_length = (*pos)->length;
223 memcpy(*data, (*pos)->data, (*pos)->length);
225 CMS_ContentInfo_free(cms_ci); cms_ci = NULL;
227 return IE_SUCCESS;
229 fail:
230 if (NULL != bio) {
231 BIO_free(bio);
233 if (NULL != cms_ci) {
234 CMS_ContentInfo_free(cms_ci);
236 return retval;