1 /* src/util.c */
2
3 #include "scep.h"
4 #include <stdio.h>
5 #include <openssl/asn1t.h>
6
scep_strerror(SCEP_ERROR err)7 char *scep_strerror(SCEP_ERROR err)
8 {
9 switch(err)
10 {
11 case SCEPE_OK:
12 return "No error";
13 case SCEPE_MEMORY:
14 return "Not enough memory available";
15 case SCEPE_UNKNOWN_CONFIGURATION:
16 return "This configuration option is not known";
17 case SCEPE_UNKOWN_OPERATION:
18 return "Operation is unknown or no operation specified";
19 case SCEPE_DUPLICATE_BIO:
20 return "Overwriting BIO not allowed. Check error log for details";
21 case SCEPE_PROTOCOL:
22 return "Invalid protocol operation";
23 case SCEPE_INVALID_CONTENT:
24 return "The content to be enveloped or contained in enveloped data structure does not meet the specifications";
25 case SCEPE_INVALID_PARAMETER:
26 return "A parameter was invalid, e.g. it was required but missing or its combination with other parameters is invalid";
27 case SCEPE_UNHANDLED:
28 return "The library could not handle this specific case and "
29 "does not know how to proceed. Please contact the developers "
30 "of the project.";
31 case SCEPE_PARAM:
32 return "Invalid or unset parameter";
33 case SCEPE_NYI:
34 return "Action is defined by protocol but client does not yet "
35 "support it. See log for details on which action is "
36 "responsible for this.";
37 case SCEPE_OPENSSL:
38 return "Error in OpenSSL. See error log for details.";
39 case SCEPE_INTERNAL:
40 return "Internal error";
41 case SCEPE_DUMMY_LAST_ERROR:
42 return "Unknown error";
43 }
44
45 /**
46 * Nifty little trick stolen from libcurl: If an error is defined in
47 * an enum but not handled by switch, gcc will complain.
48 */
49 return "Unknown error";
50 }
51
scep_fail_info_str(SCEP_FAILINFO fail_info)52 char *scep_fail_info_str(SCEP_FAILINFO fail_info)
53 {
54 switch(fail_info) {
55 case SCEP_BAD_ALG:
56 return "badAlg: Unrecognized or unsupported algorithm identifier";
57 case SCEP_BAD_MESSAGE_CHECK:
58 return "badMessageCheck: integrity check failed";
59 case SCEP_BAD_REQUEST:
60 return "badRequest: transaction not permitted or supported";
61 case SCEP_BAD_TIME:
62 return "badTime: The signingTime attribute from the PKCS#7 authenticatedAttributes was not sufficiently close to the system time";
63 case SCEP_BAD_CERT_ID:
64 return "badCertId: No certificate could be identified matching the provided criteria";
65 }
66
67 return "Unknown failInfo";
68 }
69
scep_calculate_transaction_id_pubkey(SCEP * handle,EVP_PKEY * pubkey,char ** transaction_id)70 SCEP_ERROR scep_calculate_transaction_id_pubkey(SCEP *handle, EVP_PKEY *pubkey, char **transaction_id)
71 {
72 SCEP_ERROR error = SCEPE_OK;
73 BIO *bio;
74 unsigned char *data, digest[SHA256_DIGEST_LENGTH];
75 int len, i;
76 EVP_MD_CTX *ctx = NULL;
77
78 if(!(*transaction_id = malloc(2 * SHA256_DIGEST_LENGTH + 1)))
79 return SCEPE_MEMORY;
80 memset(*transaction_id, 0, 2 * SHA256_DIGEST_LENGTH + 1);
81
82 if(!(bio = BIO_new(BIO_s_mem())))
83 {
84 error = SCEPE_MEMORY;
85 goto finally;
86 }
87
88 if(!i2d_PUBKEY_bio(bio, pubkey))
89 SCEP_ERR(SCEPE_INVALID_CONTENT, "Error converting public key, malformed?");
90
91 len = BIO_get_mem_data(bio, &data);
92 if(len == 0)
93 OSSL_ERR("Could not get data from bio");
94
95 SHA256(data, len, digest);
96 ctx = EVP_MD_CTX_create();
97 if(ctx == NULL)
98 OSSL_ERR("Could not create hash context");
99
100 if(EVP_DigestInit_ex(ctx, EVP_sha256(), NULL) == 0)
101 OSSL_ERR("Could not initialize hash context");
102
103 if(EVP_DigestUpdate(ctx, data, len) == 0)
104 OSSL_ERR("Could not read data into context");
105
106 if(EVP_DigestFinal_ex(ctx, digest, NULL) == 0)
107 OSSL_ERR("Could not finalize context");
108
109 for(i=0; i < SHA256_DIGEST_LENGTH; ++i)
110 sprintf((*transaction_id) + i * 2, "%02X", digest[i]);
111 scep_log(handle, INFO, "Generated transaction id %s", *transaction_id);
112 finally:
113 if(error != SCEPE_OK)
114 if(*transaction_id)
115 free(*transaction_id);
116 if(bio)
117 BIO_free(bio);
118 if(ctx)
119 EVP_MD_CTX_destroy(ctx);
120 return error;
121 }
122
scep_calculate_transaction_id_ias_type(SCEP * handle,PKCS7_ISSUER_AND_SERIAL * ias,char * messageType,char ** transaction_id)123 SCEP_ERROR scep_calculate_transaction_id_ias_type(SCEP *handle, PKCS7_ISSUER_AND_SERIAL *ias, char *messageType, char **transaction_id)
124 {
125 SCEP_ERROR error = SCEPE_OK;
126 unsigned char digest[SHA256_DIGEST_LENGTH], *serial_data = NULL, *issuer_data = NULL;
127 int i, serial_len, issuer_len;
128 EVP_MD_CTX *ctx = NULL;
129
130 if(!(*transaction_id = malloc(2 * SHA256_DIGEST_LENGTH + 1)))
131 return SCEPE_MEMORY;
132 memset(*transaction_id, 0, 2 * SHA256_DIGEST_LENGTH + 1);
133
134 issuer_len = ASN1_item_i2d((void *) ias->issuer, &issuer_data, ASN1_ITEM_rptr(X509_NAME));
135 if(!issuer_data)
136 SCEP_ERR(SCEPE_INVALID_CONTENT, "Error converting issuer, malformed?");
137
138 serial_len = ASN1_item_i2d((void *) ias->serial, &serial_data, ASN1_ITEM_rptr(ASN1_INTEGER));
139 if(!serial_data)
140 SCEP_ERR(SCEPE_INVALID_CONTENT, "Error converting serial, malformed?");
141
142 ctx = EVP_MD_CTX_create();
143 if(ctx == NULL)
144 OSSL_ERR("Could not create hash context");
145
146 if(EVP_DigestInit_ex(ctx, EVP_sha256(), NULL) == 0)
147 OSSL_ERR("Could not initialize hash context");
148
149 if(EVP_DigestUpdate(ctx, issuer_data, issuer_len) == 0)
150 OSSL_ERR("Could not read issuer data into context");
151
152 if(EVP_DigestUpdate(ctx, serial_data, serial_len) == 0)
153 OSSL_ERR("Could not read issuer data into context");
154
155 if(EVP_DigestUpdate(ctx, (unsigned char *) messageType, strlen(messageType)) == 0)
156 OSSL_ERR("Could not read messageType into context");
157
158 if(EVP_DigestFinal_ex(ctx, digest, NULL) == 0)
159 OSSL_ERR("Could not finalize context");
160
161 for(i=0; i < SHA256_DIGEST_LENGTH; ++i)
162 sprintf((*transaction_id) + i * 2, "%02X", digest[i]);
163 scep_log(handle, INFO, "Generated transaction id %s", *transaction_id);
164 finally:
165 if(error != SCEPE_OK)
166 if(*transaction_id)
167 free(*transaction_id);
168 if(issuer_data)
169 free(issuer_data);
170 if(serial_data)
171 free(serial_data);
172 if(ctx)
173 EVP_MD_CTX_destroy(ctx);
174 return error;
175 }
176
scep_PKCS7_base64_encode(SCEP * handle,PKCS7 * p7,char ** encoded)177 SCEP_ERROR scep_PKCS7_base64_encode(SCEP *handle, PKCS7 *p7, char **encoded)
178 {
179 BIO *outbio = NULL, *input_b64bio = NULL;
180 SCEP_ERROR error = SCEPE_OK;
181 char *tmp;
182 long data_size;
183
184 outbio = BIO_new(BIO_s_mem());
185 input_b64bio = BIO_push(BIO_new(BIO_f_base64()), outbio);
186 if(!input_b64bio || !outbio)
187 OSSL_ERR("Could not create B64 encoding BIO chain");
188
189 if(!i2d_PKCS7_bio(input_b64bio, p7))
190 OSSL_ERR("Could read data into BIO");
191 BIO_flush(input_b64bio);
192
193 if(!(data_size = BIO_get_mem_data(outbio, &tmp)))
194 OSSL_ERR("Could not copy data from BIO to output char *");
195 *encoded = malloc(data_size + 1);
196 memcpy(*encoded, tmp, data_size);
197 (*encoded)[data_size] = '\0';
198
199 finally:
200 BIO_free_all(input_b64bio);
201 return error;
202 }
203
_scep_log(SCEP * handle,SCEP_VERBOSITY verbosity,const char * file,int line,char * format,...)204 void _scep_log(SCEP *handle, SCEP_VERBOSITY verbosity, const char *file,
205 int line, char *format, ...)
206 {
207 char *full_message;
208 char *message;
209 int message_len, full_message_len;
210 va_list args;
211 char *filecopy, *filename;
212 /* we don't handle any errors here (besides checking for them).
213 * If there's not enough memory, there are bigger issues at stake
214 * than logging.
215 */
216 if(handle->configuration->log &&
217 handle->configuration->verbosity >= verbosity)
218 {
219 filecopy = strdup(file);
220 filename = basename(filecopy);
221 // create the message from format string and var args.
222 va_start(args, format);
223 message_len = vsnprintf(NULL, 0, format, args) + 1;
224 va_end(args);
225 message = malloc(message_len);
226 if(!message)
227 return;
228 va_start(args, format);
229 vsnprintf(message, message_len, format, args);
230 va_end(args);
231
232 full_message_len = snprintf(NULL, 0, "%s:%d: %s\n", filename, line, message) + 1;
233 full_message = malloc(full_message_len);
234 if(!full_message)
235 return;
236 memset(full_message, 0, full_message_len);
237 snprintf(full_message, full_message_len, "%s:%d: %s\n", filename, line, message);
238 BIO_puts(handle->configuration->log, full_message);
239 free(filecopy);
240 free(full_message);
241 free(message);
242 }
243 }
244
scep_new_selfsigned_X509(SCEP * handle,X509_REQ * req,EVP_PKEY * req_key,X509 ** cert)245 SCEP_ERROR scep_new_selfsigned_X509(
246 SCEP *handle, X509_REQ *req, EVP_PKEY *req_key, X509 **cert)
247 {
248 SCEP_ERROR error = SCEPE_OK;
249 X509 *new_cert = NULL;
250 EVP_PKEY *pub_key = NULL;
251 X509_NAME *subject = NULL;
252 ASN1_INTEGER *serial = NULL;
253
254 pub_key = X509_REQ_get_pubkey(req);
255 if(!pub_key)
256 SCEP_ERR(SCEPE_INVALID_CONTENT, "Missing public key on CSR");
257
258 subject = X509_REQ_get_subject_name(req);
259 if(!subject)
260 SCEP_ERR(SCEPE_INVALID_CONTENT, "Missing subject on CSR");
261
262 new_cert = X509_new();
263 if(!new_cert)
264 OSSL_ERR("Could not create new certificate");
265
266 if(!X509_set_version(new_cert, 2))
267 OSSL_ERR("Could not set certificate to V3");
268
269 serial = s2i_ASN1_INTEGER(NULL, "1");
270 if(!serial)
271 OSSL_ERR("Could not create serial");
272
273 if(!X509_set_serialNumber(new_cert, serial))
274 OSSL_ERR("Could not set serial number on cert");
275
276 if(!X509_set_subject_name(new_cert, subject))
277 OSSL_ERR("Could not set subject name");
278
279 if(!X509_set_issuer_name(new_cert, subject))
280 OSSL_ERR("Could not set issuer name");
281
282 if(!X509_set_pubkey(new_cert, pub_key))
283 OSSL_ERR("Could not set public key");
284
285 if(!X509_gmtime_adj(X509_get_notBefore(new_cert), 0))
286 OSSL_ERR("Could not set notBefore field");
287 if(!X509_gmtime_adj(X509_get_notAfter(new_cert),
288 SCEP_SELFSIGNED_EXPIRE_DAYS * 24 * 60 * 60))
289 OSSL_ERR("Could not set notAfter field");
290
291 if(!X509_sign(new_cert, req_key, handle->configuration->sigalg))
292 OSSL_ERR("Could not sign certificate with private key");
293 *cert = new_cert;
294 finally:
295 if(error != SCEPE_OK)
296 if(new_cert)
297 X509_free(new_cert);
298 if(pub_key)
299 EVP_PKEY_free(pub_key);
300 if(serial)
301 ASN1_INTEGER_free(serial);
302 return error;
303 }
304
X509_REQ_cmp(X509_REQ * req1,X509_REQ * req2)305 int X509_REQ_cmp(X509_REQ *req1, X509_REQ *req2)
306 {
307 #if OPENSSL_VERSION_NUMBER < 0x10100000L
308 return ASN1_STRING_cmp(req1->signature, req2->signature);
309 #else
310 const ASN1_BIT_STRING *sig1 = NULL;
311 const ASN1_BIT_STRING *sig2 = NULL;
312 X509_REQ_get0_signature(req1, &sig2, NULL);
313 X509_REQ_get0_signature(req2, &sig2, NULL);
314 return ASN1_STRING_cmp(sig1, sig2);
315 #endif
316 }
317
318 ASN1_SEQUENCE(PKCS7_ISSUER_AND_SUBJECT) = {
319 ASN1_SIMPLE(PKCS7_ISSUER_AND_SUBJECT, issuer, X509_NAME),
320 ASN1_SIMPLE(PKCS7_ISSUER_AND_SUBJECT, subject, X509_NAME)
321 } ASN1_SEQUENCE_END(PKCS7_ISSUER_AND_SUBJECT)
322
323 IMPLEMENT_ASN1_FUNCTIONS(PKCS7_ISSUER_AND_SUBJECT)
324