Convert ASCII-encoded OpenSSL errors to non-compliant user-defined encoding.
[libisds.git] / src / crypto_openssl.c
blob2bef817e353e5c003d62c05ab33ac7ba072c1d01
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/md5.h>
9 #include <openssl/pkcs7.h>
10 #include <openssl/sha.h>
11 #include <openssl/x509.h>
13 #include "isds_priv.h"
14 #include "utils.h"
17 #ifndef SHA1_DIGEST_LENGTH
18 # define SHA1_DIGEST_LENGTH 20
19 #endif /* !SHA1_DIGEST_LENGTH */
22 /* Initialise all cryptographic libraries which libisds depends on.
23 * @return IE_SUCCESS if everything went all-right. */
24 _hidden isds_error _isds_init_crypto(void)
26 ERR_load_crypto_strings();
27 //ERR_load_CMS_strings();
29 version_openssl = SSLeay_version(SSLEAY_VERSION);
31 return IE_SUCCESS;
34 /* Computes hash from @input with @length and store it into @hash.
35 * The hash algorithm is defined inside @hash.
36 * @input is input block to hash
37 * @length is @input block length in bytes
38 * @hash input algorithm, output hash value and hash length; hash value will be
39 * reallocated, it's always valid pointer or NULL (before and after call) */
40 _hidden isds_error _isds_compute_hash(const void *input,
41 const size_t length, struct isds_hash *hash)
43 void *hash_buf = NULL;
44 size_t hash_len = 0;
45 unsigned char * (*hash_func)(const unsigned char *, size_t n,
46 unsigned char *) = NULL;
48 if (((0 != length) && (NULL == input)) || (NULL == hash)) {
49 return IE_INVAL;
52 isds_log(ILF_SEC, ILL_DEBUG,
53 _("Data hash requested, length=%zu, content:\n%*s\n"
54 "End of data to hash\n"), length, length, input);
56 /* Select algorithm */
57 switch (hash->algorithm) {
58 case HASH_ALGORITHM_MD5:
59 hash_len = MD5_DIGEST_LENGTH;
60 hash_func = MD5;
61 break;
62 case HASH_ALGORITHM_SHA_1:
63 hash_len = SHA1_DIGEST_LENGTH;
64 hash_func = SHA1;
65 break;
66 case HASH_ALGORITHM_SHA_224:
67 hash_len = SHA224_DIGEST_LENGTH;
68 hash_func = SHA224;
69 break;
70 case HASH_ALGORITHM_SHA_256:
71 hash_len = SHA256_DIGEST_LENGTH;
72 hash_func = SHA256;
73 break;
74 case HASH_ALGORITHM_SHA_384:
75 hash_len = SHA384_DIGEST_LENGTH;
76 hash_func = SHA384;
77 break;
78 case HASH_ALGORITHM_SHA_512:
79 hash_len = SHA512_DIGEST_LENGTH;
80 hash_func = SHA512;
81 break;
82 default:
83 return IE_NOTSUP;
86 /* Get known the hash length and allocate buffer for hash value */
87 hash->length = hash_len;
88 hash_buf = realloc(hash->value, hash->length);
89 if (NULL == hash_buf) {
90 return IE_NOMEM;
92 hash->value = hash_buf;
94 assert(NULL != hash->value);
95 assert(NULL != hash_func);
97 /* Compute the hash */
98 hash_func(input, length, hash->value);
100 return IE_SUCCESS;
103 /* Free CMS data buffer allocated inside _isds_extract_cms_data().
104 * This is necessary because GPGME.
105 * @buffer is pointer to memory to free */
106 _hidden void _isds_cms_data_free(void *buffer)
108 free(buffer);
111 /* Extract data from CMS (successor of PKCS#7)
112 * @context is session context
113 * @cms is input block with CMS structure
114 * @cms_length is @cms block length in bytes
115 * @data are automatically reallocated bit stream with data found in @cms
116 * You must free them with _isds_cms_data_free().
117 * @data_length is length of @data in bytes */
118 _hidden isds_error _isds_extract_cms_data(struct isds_ctx *context,
119 const void *cms, const size_t cms_length,
120 void **data, size_t *data_length)
122 unsigned long err;
123 isds_error retval = IE_SUCCESS;
124 BIO *bio = NULL;
125 CMS_ContentInfo *cms_ci = NULL;
126 const ASN1_OBJECT *asn1_obj;
127 ASN1_OCTET_STRING **pos;
128 int nid;
129 char *locale_str;
131 assert(NULL != context);
133 if ((NULL == cms) || (0 == cms_length) ||
134 (NULL == data) || (NULL == data_length)) {
135 return IE_INVAL;
138 zfree(*data);
139 *data_length = 0;
141 bio = BIO_new_mem_buf((void *) cms, cms_length);
142 if (NULL == bio) {
143 isds_log_message(context, _("Creating CMS reader BIO failed."));
144 while (0 != (err = ERR_get_error())) {
145 locale_str = _isds_utf82locale(ERR_error_string(err, NULL));
146 if (NULL != locale_str) {
147 isds_log_message(context, locale_str);
148 free(locale_str);
151 retval = IE_ERROR;
152 goto fail;
155 cms_ci = d2i_CMS_bio(bio, NULL);
156 if (NULL == cms_ci) {
157 fprintf(stderr, "Cannot parse CMS.\n");
158 isds_log_message(context, _("Cannot parse CMS."));
159 while (0 != (err = ERR_get_error())) {
160 locale_str = _isds_utf82locale(ERR_error_string(err, NULL));
161 if (NULL != locale_str) {
162 isds_log_message(context, locale_str);
163 free(locale_str);
166 retval = IE_ERROR;
167 goto fail;
170 BIO_free(bio); bio = NULL;
172 asn1_obj = CMS_get0_type(cms_ci);
173 nid = OBJ_obj2nid(asn1_obj);
174 switch (nid) {
175 case NID_pkcs7_data:
176 case NID_id_smime_ct_compressedData:
177 case NID_id_smime_ct_authData:
178 case NID_pkcs7_enveloped:
179 case NID_pkcs7_encrypted:
180 case NID_pkcs7_digest:
181 assert(0);
182 retval = IE_ERROR;
183 goto fail;
184 break;
185 case NID_pkcs7_signed:
186 pos = CMS_get0_content(cms_ci);
187 if ((NULL == pos) || (NULL == *pos)) {
188 assert(0);
189 retval = IE_ERROR;
190 goto fail;
192 break;
193 default:
194 assert(0);
195 retval = IE_ERROR;
196 goto fail;
197 break;
200 *data = malloc((*pos)->length);
201 if (NULL == *data) {
202 retval = IE_NOMEM;
203 goto fail;
205 *data_length = (*pos)->length;
206 memcpy(*data, (*pos)->data, (*pos)->length);
208 CMS_ContentInfo_free(cms_ci); cms_ci = NULL;
210 return IE_SUCCESS;
212 fail:
213 if (NULL != bio) {
214 BIO_free(bio);
216 if (NULL != cms_ci) {
217 CMS_ContentInfo_free(cms_ci);
219 return retval;