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