1 /*
2  * Copyright 2011-2013 Red Hat, Inc.
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; version 2 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Author(s): Peter Jones <pjones@redhat.com>
18  */
19 
20 #include <assert.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <time.h>
24 #include <unistd.h>
25 #include <stdarg.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <syslog.h>
29 
30 #include "pesign.h"
31 
32 #include <prerror.h>
33 #include <nss.h>
34 #include <secport.h>
35 #include <secpkcs7.h>
36 #include <secder.h>
37 #include <keyhi.h>
38 #include <base64.h>
39 #include <pk11pub.h>
40 #include <secerr.h>
41 #include <certt.h>
42 
43 struct digest_param {
44 	char *name;
45 	SECOidTag digest_tag;
46 	SECOidTag signature_tag;
47 	SECOidTag digest_encryption_tag;
48 	const efi_guid_t *efi_guid;
49 	int size;
50 };
51 
52 static struct digest_param digest_params[] = {
53 	{.name = "sha256",
54 	 .digest_tag = SEC_OID_SHA256,
55 	 .signature_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION,
56 	 .digest_encryption_tag = SEC_OID_PKCS1_RSA_ENCRYPTION,
57 	 .efi_guid = &efi_guid_sha256,
58 	 .size = 32
59 	},
60 #if 1
61 	{.name = "sha1",
62 	 .digest_tag = SEC_OID_SHA1,
63 	 .signature_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION,
64 	 .digest_encryption_tag = SEC_OID_PKCS1_RSA_ENCRYPTION,
65 	 .efi_guid = &efi_guid_sha1,
66 	 .size = 20
67 	},
68 #endif
69 };
70 static int n_digest_params = sizeof (digest_params) / sizeof (digest_params[0]);
71 
72 SECOidTag
digest_get_digest_oid(cms_context * cms)73 digest_get_digest_oid(cms_context *cms)
74 {
75 	int i = cms->selected_digest;
76 	return digest_params[i].digest_tag;
77 }
78 
79 SECOidTag
digest_get_encryption_oid(cms_context * cms)80 digest_get_encryption_oid(cms_context *cms)
81 {
82 	int i = cms->selected_digest;
83 	return digest_params[i].digest_encryption_tag;
84 }
85 
86 SECOidTag
digest_get_signature_oid(cms_context * cms)87 digest_get_signature_oid(cms_context *cms)
88 {
89 	int i = cms->selected_digest;
90 	return digest_params[i].signature_tag;
91 }
92 
93 int
digest_get_digest_size(cms_context * cms)94 digest_get_digest_size(cms_context *cms)
95 {
96 	int i = cms->selected_digest;
97 	return digest_params[i].size;
98 }
99 
100 void
teardown_digests(cms_context * ctx)101 teardown_digests(cms_context *ctx)
102 {
103 	struct digest *digests = ctx->digests;
104 
105 	if (!digests)
106 		return;
107 
108 	for (int i = 0; i < n_digest_params; i++) {
109 		if (digests[i].pk11ctx) {
110 			PK11_Finalize(digests[i].pk11ctx);
111 			PK11_DestroyContext(digests[i].pk11ctx, PR_TRUE);
112 		}
113 		if (digests[i].pe_digest) {
114 			/* XXX sure seems like we should be freeing it here,
115 			 * but that's segfaulting, and we know it'll get
116 			 * cleaned up with PORT_FreeArena a couple of lines
117 			 * down.
118 			 */
119 			digests[i].pe_digest = NULL;
120 		}
121 	}
122 	PORT_Free(digests);
123 	ctx->digests = NULL;
124 }
125 
126 static int
127 __attribute__ ((format (printf, 3, 4)))
cms_common_log(cms_context * ctx,int priority,char * fmt,...)128 cms_common_log(cms_context *ctx, int priority, char *fmt, ...)
129 {
130 	va_list ap;
131 	FILE *out = priority & LOG_ERR ? stderr : stdout;
132 
133 	va_start(ap, fmt);
134 	int rc = vfprintf(out, fmt, ap);
135 	fprintf(out, "\n");
136 
137 	va_end(ap);
138 	return rc;
139 }
140 
141 int
cms_context_init(cms_context * cms)142 cms_context_init(cms_context *cms)
143 {
144 	memset(cms, '\0', sizeof (*cms));
145 
146 	cms->log = cms_common_log;
147 
148 	cms->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
149 	if (!cms->arena)
150 		cmsreterr(-1, cms, "could not create cryptographic arena");
151 
152 	cms->selected_digest = -1;
153 
154 	return 0;
155 }
156 
157 void
cms_context_fini(cms_context * cms)158 cms_context_fini(cms_context *cms)
159 {
160 	if (cms->cert) {
161 		CERT_DestroyCertificate(cms->cert);
162 		cms->cert = NULL;
163 	}
164 
165 	if (cms->privkey) {
166 		free(cms->privkey);
167 		cms->privkey = NULL;
168 	}
169 
170 	/* These were freed when the arena was destroyed */
171 	if (cms->tokenname)
172 		cms->tokenname = NULL;
173 	if (cms->certname)
174 		cms->certname = NULL;
175 
176 	if (cms->newsig.data) {
177 		free_poison(cms->newsig.data, cms->newsig.len);
178 		free(cms->newsig.data);
179 		memset(&cms->newsig, '\0', sizeof (cms->newsig));
180 	}
181 
182 	cms->selected_digest = -1;
183 
184 	if (cms->ci_digest) {
185 		free_poison(cms->ci_digest->data, cms->ci_digest->len);
186 		/* XXX sure seems like we should be freeing it here, but
187 		 * that's segfaulting, and we know it'll get cleaned up with
188 		 * PORT_FreeArena a couple of lines down.
189 		 */
190 		cms->ci_digest = NULL;
191 	}
192 
193 	teardown_digests(cms);
194 
195 	if (cms->raw_signed_attrs) {
196 		free_poison(cms->raw_signed_attrs->data,
197 				cms->raw_signed_attrs->len);
198 		/* XXX sure seems like we should be freeing it here, but
199 		 * that's segfaulting, and we know it'll get cleaned up with
200 		 * PORT_FreeArena a couple of lines down.
201 		 */
202 		cms->raw_signed_attrs = NULL;
203 	}
204 
205 	if (cms->raw_signature) {
206 		free_poison(cms->raw_signature->data,
207 				cms->raw_signature->len);
208 		/* XXX sure seems like we should be freeing it here, but
209 		 * that's segfaulting, and we know it'll get cleaned up with
210 		 * PORT_FreeArena a couple of lines down.
211 		 */
212 		cms->raw_signature = NULL;
213 	}
214 
215 	for (int i = 0; i < cms->num_signatures; i++) {
216 		free(cms->signatures[i]->data);
217 		free(cms->signatures[i]);
218 	}
219 
220 	xfree(cms->signatures);
221 	cms->num_signatures = 0;
222 
223 	if (cms->authbuf) {
224 		xfree(cms->authbuf);
225 		cms->authbuf_len = 0;
226 	}
227 
228 	PORT_FreeArena(cms->arena, PR_TRUE);
229 	memset(cms, '\0', sizeof(*cms));
230 	xfree(cms);
231 }
232 
233 int
cms_context_alloc(cms_context ** cmsp)234 cms_context_alloc(cms_context **cmsp)
235 {
236 	cms_context *cms = calloc(1, sizeof (*cms));
237 	if (!cms)
238 		return -1;
239 
240 	int rc = cms_context_init(cms);
241 	if (rc < 0) {
242 		save_errno(free(cms));
243 		return -1;
244 	}
245 	*cmsp = cms;
246 	return 0;
247 }
248 
cms_set_pw_callback(cms_context * cms,PK11PasswordFunc func)249 void cms_set_pw_callback(cms_context *cms, PK11PasswordFunc func)
250 {
251 	cms->func = func;
252 }
253 
cms_set_pw_data(cms_context * cms,void * pwdata)254 void cms_set_pw_data(cms_context *cms, void *pwdata)
255 {
256 	cms->pwdata = pwdata;
257 }
258 
259 int
set_digest_parameters(cms_context * cms,char * name)260 set_digest_parameters(cms_context *cms, char *name)
261 {
262 	if (strcmp(name, "help")) {
263 		for (int i = 0; i < n_digest_params; i++) {
264 			if (!strcmp(name, digest_params[i].name)) {
265 				cms->selected_digest = i;
266 				return 0;
267 			}
268 		}
269 	} else {
270 		printf("Supported digests: ");
271 		for (int i = 0; digest_params[i].name != NULL; i++) {
272 			printf("%s ", digest_params[i].name);
273 		}
274 		printf("\n");
275 	}
276 	return -1;
277 }
278 
279 struct cbdata {
280 	CERTCertificate *cert;
281 	PK11SlotListElement *psle;
282 	secuPWData *pwdata;
283 };
284 
285 static SECStatus
is_valid_cert(CERTCertificate * cert,void * data)286 is_valid_cert(CERTCertificate *cert, void *data)
287 {
288 	struct cbdata *cbdata = (struct cbdata *)data;
289 
290 	PK11SlotInfo *slot = cbdata->psle->slot;
291 	void *pwdata = cbdata->pwdata;
292 
293 	SECKEYPrivateKey *privkey = NULL;
294 	privkey = PK11_FindPrivateKeyFromCert(slot, cert, pwdata);
295 	if (privkey != NULL) {
296 		cbdata->cert = cert;
297 		SECKEY_DestroyPrivateKey(privkey);
298 		return SECSuccess;
299 	}
300 	return SECFailure;
301 }
302 
303 static SECStatus
is_valid_cert_without_private_key(CERTCertificate * cert,void * data)304 is_valid_cert_without_private_key(CERTCertificate *cert, void *data)
305 {
306 	struct cbdata *cbdata = (struct cbdata *)data;
307 	if (cert) {
308 		cbdata->cert = cert;
309 		return SECSuccess;
310 	}
311 	return SECFailure;
312 }
313 
314 int
is_issuer_of(CERTCertificate * c0,CERTCertificate * c1)315 is_issuer_of(CERTCertificate *c0, CERTCertificate *c1)
316 {
317 	if (c0->derSubject.len != c1->derIssuer.len)
318 		return 0;
319 
320 	if (memcmp(c0->derSubject.data, c1->derIssuer.data, c0->derSubject.len))
321 		return 0;
322 	return 1;
323 }
324 
325 /* This is the dumbest function ever, but we need it anyway, because nss
326  * is garbage. */
327 static void
PK11_DestroySlotListElement(PK11SlotList * slots,PK11SlotListElement ** psle)328 PK11_DestroySlotListElement(PK11SlotList *slots, PK11SlotListElement **psle)
329 {
330 	while (psle && *psle)
331 		*psle = PK11_GetNextSafe(slots, *psle, PR_FALSE);
332 }
333 
334 int
unlock_nss_token(cms_context * cms)335 unlock_nss_token(cms_context *cms)
336 {
337 	secuPWData pwdata_val = { 0, 0 };
338 	void *pwdata = cms->pwdata ? cms->pwdata : &pwdata_val;
339 	PK11_SetPasswordFunc(cms->func ? cms->func : SECU_GetModulePassword);
340 
341 	PK11SlotList *slots = NULL;
342 	slots = PK11_GetAllTokens(CKM_RSA_PKCS, PR_FALSE, PR_TRUE, pwdata);
343 	if (!slots)
344 		cmsreterr(-1, cms, "could not get pk11 token list");
345 
346 	PK11SlotListElement *psle = NULL;
347 	psle = PK11_GetFirstSafe(slots);
348 	if (!psle) {
349 		save_port_err(PK11_FreeSlotList(slots));
350 		cmsreterr(-1, cms, "could not get pk11 safe");
351 	}
352 
353 	while (psle) {
354 		if (!strcmp(cms->tokenname, PK11_GetTokenName(psle->slot)))
355 			break;
356 
357 		psle = PK11_GetNextSafe(slots, psle, PR_FALSE);
358 	}
359 
360 	if (!psle) {
361 		save_port_err(PK11_FreeSlotList(slots));
362 		cms->log(cms, LOG_ERR, "could not find token \"%s\"",
363 			cms->tokenname);
364 		return -1;
365 	}
366 
367 	SECStatus status;
368 	if (PK11_NeedLogin(psle->slot) &&
369 			!PK11_IsLoggedIn(psle->slot, pwdata)) {
370 		status = PK11_Authenticate(psle->slot, PR_TRUE, pwdata);
371 		if (status != SECSuccess) {
372 			PK11_DestroySlotListElement(slots, &psle);
373 			PK11_FreeSlotList(slots);
374 			cms->log(cms, LOG_ERR, "authentication failed for "
375 				"token \"%s\"", cms->tokenname);
376 			return -1;
377 		}
378 	}
379 
380 	PK11_DestroySlotListElement(slots, &psle);
381 	PK11_FreeSlotList(slots);
382 	return 0;
383 }
384 
385 int
find_certificate(cms_context * cms,int needs_private_key)386 find_certificate(cms_context *cms, int needs_private_key)
387 {
388 	if (!cms->certname || !*cms->certname) {
389 		cms->log(cms, LOG_ERR, "no certificate name specified");
390 		return -1;
391 	}
392 
393 	secuPWData pwdata_val = { 0, 0 };
394 	void *pwdata = cms->pwdata ? cms->pwdata : &pwdata_val;
395 	PK11_SetPasswordFunc(cms->func ? cms->func : SECU_GetModulePassword);
396 
397 	PK11SlotList *slots = NULL;
398 	slots = PK11_GetAllTokens(CKM_RSA_PKCS, PR_FALSE, PR_TRUE, pwdata);
399 	if (!slots)
400 		cmsreterr(-1, cms, "could not get pk11 token list");
401 
402 	PK11SlotListElement *psle = NULL;
403 	psle = PK11_GetFirstSafe(slots);
404 	if (!psle) {
405 		save_port_err(PK11_FreeSlotList(slots));
406 		cmsreterr(-1, cms, "could not get pk11 safe");
407 	}
408 
409 	while (psle) {
410 		if (!strcmp(cms->tokenname, PK11_GetTokenName(psle->slot)))
411 			break;
412 
413 		psle = PK11_GetNextSafe(slots, psle, PR_FALSE);
414 	}
415 
416 	if (!psle) {
417 		save_port_err(PK11_FreeSlotList(slots));
418 		cms->log(cms, LOG_ERR, "could not find token \"%s\"",
419 			cms->tokenname);
420 		return -1;
421 	}
422 
423 	SECStatus status;
424 	if (PK11_NeedLogin(psle->slot) && !PK11_IsLoggedIn(psle->slot, pwdata)) {
425 		status = PK11_Authenticate(psle->slot, PR_TRUE, pwdata);
426 		if (status != SECSuccess) {
427 			PK11_DestroySlotListElement(slots, &psle);
428 			PK11_FreeSlotList(slots);
429 			cms->log(cms, LOG_ERR, "authentication failed for "
430 				"token \"%s\"", cms->tokenname);
431 			return -1;
432 		}
433 	}
434 
435 	CERTCertList *certlist = NULL;
436 	certlist = PK11_ListCertsInSlot(psle->slot);
437 	if (!certlist) {
438 		save_port_err(
439 			PK11_DestroySlotListElement(slots, &psle);
440 			PK11_FreeSlotList(slots));
441 		cmsreterr(-1, cms, "could not get certificate list");
442 	}
443 
444 	SECItem nickname = {
445 		.data = (void *)cms->certname,
446 		.len = strlen(cms->certname) + 1,
447 		.type = siUTF8String,
448 	};
449 	struct cbdata cbdata = {
450 		.cert = NULL,
451 		.psle = psle,
452 		.pwdata = pwdata,
453 	};
454 
455 	if (needs_private_key) {
456 		status = PK11_TraverseCertsForNicknameInSlot(&nickname,
457 					psle->slot, is_valid_cert, &cbdata);
458 	} else {
459 		status = PK11_TraverseCertsForNicknameInSlot(&nickname,
460 					psle->slot,
461 					is_valid_cert_without_private_key,
462 					&cbdata);
463 	}
464 	if (cbdata.cert == NULL) {
465 		save_port_err(
466 			CERT_DestroyCertList(certlist);
467 			PK11_DestroySlotListElement(slots, &psle);
468 			PK11_FreeSlotList(slots));
469 		cmsreterr(-1, cms, "could not find certificate in list");
470 	}
471 
472 	cms->cert = CERT_DupCertificate(cbdata.cert);
473 
474 	PK11_DestroySlotListElement(slots, &psle);
475 	PK11_FreeSlotList(slots);
476 	CERT_DestroyCertList(certlist);
477 
478 	return 0;
479 }
480 
481 int
find_slot_for_token(cms_context * cms,PK11SlotInfo ** slot)482 find_slot_for_token(cms_context *cms, PK11SlotInfo **slot)
483 {
484 	if (!cms->tokenname) {
485 		cms->log(cms, LOG_ERR, "no token name specified");
486 		return -1;
487 	}
488 
489 	secuPWData pwdata_val = { 0, 0 };
490 	void *pwdata = cms->pwdata ? cms->pwdata : &pwdata_val;
491 	PK11_SetPasswordFunc(cms->func ? cms->func : SECU_GetModulePassword);
492 
493 	PK11SlotList *slots = NULL;
494 	slots = PK11_GetAllTokens(CKM_RSA_PKCS, PR_FALSE, PR_TRUE, pwdata);
495 	if (!slots)
496 		cmsreterr(-1, cms, "could not get pk11 token list");
497 
498 	PK11SlotListElement *psle = NULL;
499 	psle = PK11_GetFirstSafe(slots);
500 	if (!psle) {
501 		save_port_err(PK11_FreeSlotList(slots));
502 		cmsreterr(-1, cms, "could not get pk11 safe");
503 	}
504 
505 	while (psle) {
506 		if (!strcmp(cms->tokenname, PK11_GetTokenName(psle->slot)))
507 			break;
508 
509 		psle = PK11_GetNextSafe(slots, psle, PR_FALSE);
510 	}
511 
512 	if (!psle) {
513 		save_port_err(PK11_FreeSlotList(slots));
514 		cms->log(cms, LOG_ERR, "could not find token \"%s\"",
515 			cms->tokenname);
516 		return -1;
517 	}
518 
519 	SECStatus status;
520 	if (PK11_NeedLogin(psle->slot) && !PK11_IsLoggedIn(psle->slot, pwdata)) {
521 		status = PK11_Authenticate(psle->slot, PR_TRUE, pwdata);
522 		if (status != SECSuccess) {
523 			PK11_DestroySlotListElement(slots, &psle);
524 			PK11_FreeSlotList(slots);
525 			cms->log(cms, LOG_ERR, "authentication failed for "
526 				"token \"%s\"", cms->tokenname);
527 			return -1;
528 		}
529 	}
530 	*slot = psle->slot;
531 	return 0;
532 }
533 
534 int
find_named_certificate(cms_context * cms,char * name,CERTCertificate ** cert)535 find_named_certificate(cms_context *cms, char *name, CERTCertificate **cert)
536 {
537 	if (!name) {
538 		cms->log(cms, LOG_ERR, "no certificate name specified");
539 		return -1;
540 	}
541 
542 	secuPWData pwdata_val = { 0, 0 };
543 	void *pwdata = cms->pwdata ? cms->pwdata : &pwdata_val;
544 	PK11_SetPasswordFunc(cms->func ? cms->func : SECU_GetModulePassword);
545 
546 	PK11SlotList *slots = NULL;
547 	slots = PK11_GetAllTokens(CKM_RSA_PKCS, PR_FALSE, PR_TRUE, pwdata);
548 	if (!slots)
549 		cmsreterr(-1, cms, "could not get pk11 token list");
550 
551 	PK11SlotListElement *psle = NULL;
552 	psle = PK11_GetFirstSafe(slots);
553 	if (!psle) {
554 		save_port_err(PK11_FreeSlotList(slots));
555 		cmsreterr(-1, cms, "could not get pk11 safe");
556 	}
557 
558 	while (psle) {
559 		if (!strcmp(cms->tokenname, PK11_GetTokenName(psle->slot)))
560 			break;
561 
562 		psle = PK11_GetNextSafe(slots, psle, PR_FALSE);
563 	}
564 
565 	if (!psle) {
566 		save_port_err(PK11_FreeSlotList(slots));
567 		cms->log(cms, LOG_ERR, "could not find token \"%s\"",
568 			cms->tokenname);
569 		return -1;
570 	}
571 
572 	SECStatus status;
573 	if (PK11_NeedLogin(psle->slot) && !PK11_IsLoggedIn(psle->slot, pwdata)) {
574 		status = PK11_Authenticate(psle->slot, PR_TRUE, pwdata);
575 		if (status != SECSuccess) {
576 			PK11_DestroySlotListElement(slots, &psle);
577 			PK11_FreeSlotList(slots);
578 			cms->log(cms, LOG_ERR, "authentication failed for "
579 				"token \"%s\"", cms->tokenname);
580 			return -1;
581 		}
582 	}
583 
584 	CERTCertList *certlist = NULL;
585 	certlist = PK11_ListCertsInSlot(psle->slot);
586 	if (!certlist) {
587 		save_port_err(
588 			PK11_DestroySlotListElement(slots, &psle);
589 			PK11_FreeSlotList(slots));
590 		cmsreterr(-1, cms, "could not get certificate list");
591 	}
592 
593 	CERTCertListNode *node = NULL;
594         for (node = CERT_LIST_HEAD(certlist); !CERT_LIST_END(node,certlist);
595 						node = CERT_LIST_NEXT(node)) {
596 		if (!strcmp(node->cert->subjectName, name))
597 			break;
598 	}
599 	/* If we're looking up the issuer of some cert, and the issuer isn't
600 	 * in the database, we'll get back what is essentially a template
601 	 * that's in NSS's cache waiting to be filled out.  We can't use that,
602 	 * it'll just cause CERT_DupCertificate() to segfault. */
603 	if (CERT_LIST_END(node, certlist)
604 			|| !node->cert || !node->cert->derCert.data
605 			|| !node->cert->derCert.len
606 			|| !node->cert->derIssuer.data
607 			|| !node->cert->derIssuer.len) {
608 		PK11_DestroySlotListElement(slots, &psle);
609 		PK11_FreeSlotList(slots);
610 		CERT_DestroyCertList(certlist);
611 
612 		return -1;
613 	}
614 
615 
616 
617 	*cert = CERT_DupCertificate(node->cert);
618 
619 	PK11_DestroySlotListElement(slots, &psle);
620 	PK11_FreeSlotList(slots);
621 	CERT_DestroyCertList(certlist);
622 
623 	return 0;
624 }
625 
626 int
generate_string(cms_context * cms,SECItem * der,char * str)627 generate_string(cms_context *cms, SECItem *der, char *str)
628 {
629 	SECItem input;
630 
631 	input.data = (void *)str;
632 	input.len = strlen(str);
633 	input.type = siBMPString;
634 
635 	void *ret;
636 	ret = SEC_ASN1EncodeItem(cms->arena, der, &input,
637 						SEC_PrintableStringTemplate);
638 	if (ret == NULL)
639 		cmsreterr(-1, cms, "could not encode string");
640 	return 0;
641 }
642 
643 static SEC_ASN1Template IntegerTemplate[] = {
644 	{.kind = SEC_ASN1_INTEGER,
645 	 .offset = 0,
646 	 .sub = NULL,
647 	 .size = sizeof(long),
648 	},
649 	{ 0 },
650 };
651 
652 int
generate_integer(cms_context * cms,SECItem * der,unsigned long integer)653 generate_integer(cms_context *cms, SECItem *der, unsigned long integer)
654 {
655 	void *ret;
656 
657 	uint32_t u32;
658 
659 	SECItem input = {
660 		.data = (void *)&integer,
661 		.len = sizeof(integer),
662 		.type = siUnsignedInteger,
663 	};
664 
665 	if (integer < 0x100000000) {
666 		u32 = integer & 0xffffffffUL;
667 		input.data = (void *)&u32;
668 		input.len = sizeof(u32);
669 	}
670 
671 	ret = SEC_ASN1EncodeItem(cms->arena, der, &input, IntegerTemplate);
672 	if (ret == NULL)
673 		cmsreterr(-1, cms, "could not encode data");
674 	return 0;
675 }
676 
677 int
generate_time(cms_context * cms,SECItem * encoded,time_t when)678 generate_time(cms_context *cms, SECItem *encoded, time_t when)
679 {
680 	static char timebuf[32];
681 	SECItem whenitem = {.type = SEC_ASN1_UTC_TIME,
682 			 .data = (unsigned char *)timebuf,
683 			 .len = 0
684 	};
685 	struct tm *tm;
686 
687 	tm = gmtime(&when);
688 
689 	whenitem.len = snprintf(timebuf, 32, "%02d%02d%02d%02d%02d%02dZ",
690 		tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
691 		tm->tm_hour, tm->tm_min, tm->tm_sec);
692 	if (whenitem.len == 32)
693 		cmsreterr(-1, cms, "could not encode timestamp");
694 
695 	if (SEC_ASN1EncodeItem(cms->arena, encoded, &whenitem,
696 			SEC_UTCTimeTemplate) == NULL)
697 		cmsreterr(-1, cms, "could not encode timestamp");
698 	return 0;
699 }
700 
701 static SEC_ASN1Template EmptySequenceTemplate[] = {
702 	{
703 	.kind = SEC_ASN1_SEQUENCE,
704 	.offset = 0,
705 	.sub = NULL,
706 	.size = 0
707 	},
708 	{ 0, }
709 };
710 
711 int
generate_empty_sequence(cms_context * cms,SECItem * encoded)712 generate_empty_sequence(cms_context *cms, SECItem *encoded)
713 {
714 	SECItem empty = {.type = SEC_ASN1_SEQUENCE,
715 			 .data = NULL,
716 			 .len = 0
717 	};
718 	void *ret;
719 	ret = SEC_ASN1EncodeItem(cms->arena, encoded, &empty,
720 							EmptySequenceTemplate);
721 	if (ret == NULL)
722 		cmsreterr(-1, cms, "could not encode empty sequence");
723 	return 0;
724 }
725 
726 static SEC_ASN1Template ContextSpecificSequence[] = {
727 	{
728 	.kind = SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_EXPLICIT,
729 	.offset = 0,
730 	.sub = &SEC_AnyTemplate,
731 	.size = sizeof (SECItem),
732 	},
733 	{ 0 }
734 };
735 
736 int
make_context_specific(cms_context * cms,int ctxt,SECItem * encoded,SECItem * original)737 make_context_specific(cms_context *cms, int ctxt, SECItem *encoded,
738 			SECItem *original)
739 {
740 	void *rv;
741 	ContextSpecificSequence[0].kind = SEC_ASN1_EXPLICIT |
742 					  SEC_ASN1_CONTEXT_SPECIFIC | ctxt;
743 
744 	rv = SEC_ASN1EncodeItem(cms->arena, encoded, original,
745 				ContextSpecificSequence);
746 	if (rv == NULL)
747 		cmsreterr(-1, cms, "could not encode context specific data");
748 	return 0;
749 }
750 
751 int
generate_octet_string(cms_context * cms,SECItem * encoded,SECItem * original)752 generate_octet_string(cms_context *cms, SECItem *encoded, SECItem *original)
753 {
754 	if (content_is_empty(original->data, original->len)) {
755 		cms->log(cms, LOG_ERR, "content is empty, not encoding");
756 		return -1;
757 	}
758 	if (SEC_ASN1EncodeItem(cms->arena, encoded, original,
759 			SEC_OctetStringTemplate) == NULL)
760 		cmsreterr(-1, cms, "could not encode octet string");
761 
762 	return 0;
763 }
764 
765 int
generate_object_id(cms_context * cms,SECItem * der,SECOidTag tag)766 generate_object_id(cms_context *cms, SECItem *der, SECOidTag tag)
767 {
768 	SECOidData *oid;
769 
770 	oid = SECOID_FindOIDByTag(tag);
771 	if (!oid)
772 		cmsreterr(-1, cms, "could not find OID");
773 
774 	void *ret;
775 	ret = SEC_ASN1EncodeItem(cms->arena, der, &oid->oid,
776 						SEC_ObjectIDTemplate);
777 	if (ret == NULL)
778 		cmsreterr(-1, cms, "could not encode ODI");
779 	return 0;
780 }
781 
782 int
generate_algorithm_id(cms_context * cms,SECAlgorithmID * idp,SECOidTag tag)783 generate_algorithm_id(cms_context *cms, SECAlgorithmID *idp, SECOidTag tag)
784 {
785 	SECAlgorithmID id;
786 
787 	if (!idp)
788 		return -1;
789 
790 	SECOidData *oiddata;
791 	oiddata = SECOID_FindOIDByTag(tag);
792 	if (!oiddata) {
793 		PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
794 		return -1;
795 	}
796 	if (SECITEM_CopyItem(cms->arena, &id.algorithm, &oiddata->oid))
797 		return -1;
798 
799 	SECITEM_AllocItem(cms->arena, &id.parameters, 2);
800 	if (id.parameters.data == NULL)
801 		goto err;
802 	id.parameters.data[0] = SEC_ASN1_NULL;
803 	id.parameters.data[1] = 0;
804 	id.parameters.type = siBuffer;
805 
806 	memcpy(idp, &id, sizeof (id));
807 	return 0;
808 
809 err:
810 	SECITEM_FreeItem(&id.algorithm, PR_FALSE);
811 	return -1;
812 }
813 
814 int
encode_algorithm_id(cms_context * cms,SECItem * der,SECOidTag tag)815 encode_algorithm_id(cms_context *cms, SECItem *der, SECOidTag tag)
816 {
817 	SECAlgorithmID id;
818 
819 	int rc = generate_algorithm_id(cms, &id, tag);
820 	if (rc < 0)
821 		return rc;
822 
823 	void *ret;
824 	ret = SEC_ASN1EncodeItem(cms->arena, der, &id,
825 						SECOID_AlgorithmIDTemplate);
826 	if (ret == NULL)
827 		cmsreterr(-1, cms, "could not encode Algorithm ID");
828 
829 	return 0;
830 }
831 
832 typedef struct {
833 	/* L"<<<Obsolete>>>" no nul */
834 	SECItem unicode;
835 } SpcString;
836 
837 /* Generate DER for SpcString, which is always "<<<Obsolete>>>" in UCS-2.
838  * Irony abounds. Needs to decode like this:
839  *        [0]  (28)
840  *           00 3c 00 3c 00 3c 00 4f 00 62 00 73 00 6f 00
841  *           6c 00 65 00 74 00 65 00 3e 00 3e 00 3e
842  */
843 static SEC_ASN1Template SpcStringTemplate[] = {
844 	{
845 	.kind = SEC_ASN1_CONTEXT_SPECIFIC | 0,
846 	.offset = offsetof(SpcString, unicode),
847 	.sub = &SEC_BMPStringTemplate,
848 	.size = sizeof (SECItem),
849 	},
850 	{ 0, }
851 };
852 
853 int
generate_spc_string(cms_context * cms,SECItem * ssp,char * str,int len)854 generate_spc_string(cms_context *cms, SECItem *ssp, char *str, int len)
855 {
856 	SpcString ss;
857 	memset(&ss, '\0', sizeof (ss));
858 
859 	SECITEM_AllocItem(cms->arena, &ss.unicode, len);
860 	if (len != 0) {
861 		if (!ss.unicode.data)
862 			cmsreterr(-1, cms, "could not allocate memory");
863 
864 		memcpy(ss.unicode.data, str, len);
865 	}
866 	ss.unicode.type = siBMPString;
867 
868 	if (SEC_ASN1EncodeItem(cms->arena, ssp, &ss, SpcStringTemplate) == NULL)
869 		cmsreterr(-1, cms, "could not encode SpcString");
870 
871 	return 0;
872 }
873 
874 /* Generate the SpcLink DER. Awesomely, this needs to decode as:
875  *                      C-[2]  (30)
876  * That is all.
877  */
878 SEC_ASN1Template SpcLinkTemplate[] = {
879 	{
880 	.kind = SEC_ASN1_CHOICE,
881 	.offset = offsetof(SpcLink, type),
882 	.sub = NULL,
883 	.size = sizeof (SpcLink)
884 	},
885 	{
886 	.kind = SEC_ASN1_CONTEXT_SPECIFIC | 0 |
887 		SEC_ASN1_EXPLICIT,
888 	.offset = offsetof(SpcLink, url),
889 	.sub = &SEC_AnyTemplate,
890 	.size = SpcLinkTypeUrl,
891 	},
892 	{
893 	.kind = SEC_ASN1_CONSTRUCTED |
894 		SEC_ASN1_CONTEXT_SPECIFIC | 2,
895 	.offset = offsetof(SpcLink, file),
896 	.sub = &SpcStringTemplate,
897 	.size = SpcLinkTypeFile,
898 	},
899 	{ 0, }
900 };
901 
902 int
generate_spc_link(cms_context * cms,SpcLink * slp,SpcLinkType link_type,void * link_data,size_t link_data_size)903 generate_spc_link(cms_context *cms, SpcLink *slp, SpcLinkType link_type,
904 		void *link_data, size_t link_data_size)
905 {
906 	SpcLink sl;
907 	memset(&sl, '\0', sizeof (sl));
908 
909 	sl.type = link_type;
910 	switch (sl.type) {
911 	case SpcLinkTypeFile: {
912 		int rc = generate_spc_string(cms, &sl.file, link_data,
913 					link_data_size);
914 		if (rc < 0)
915 			return rc;
916 		break;
917 	}
918 	case SpcLinkTypeUrl:
919 		sl.url.type = siBuffer;
920 		sl.url.data = link_data;
921 		sl.url.len = link_data_size;
922 		break;
923 	default:
924 		cms->log(cms, LOG_ERR, "Invalid SpcLinkType");
925 		return -1;
926 	};
927 
928 	memcpy(slp, &sl, sizeof (sl));
929 	return 0;
930 }
931 
932 static int
check_pointer_and_size(Pe * pe,void * ptr,size_t size)933 check_pointer_and_size(Pe *pe, void *ptr, size_t size)
934 {
935 	void *map = NULL;
936 	size_t map_size = 0;
937 
938 	map = pe_rawfile(pe, &map_size);
939 	if (!map || map_size < 1)
940 		return 0;
941 
942 	if ((uintptr_t)ptr < (uintptr_t)map)
943 		return 0;
944 
945 	if ((uintptr_t)ptr + size > (uintptr_t)map + map_size)
946 		return 0;
947 
948 	if (ptr <= map && size >= map_size)
949 		return 0;
950 
951 	return 1;
952 }
953 
954 int
generate_digest_begin(cms_context * cms)955 generate_digest_begin(cms_context *cms)
956 {
957 	struct digest *digests = NULL;
958 
959 	if (cms->digests) {
960 		digests = cms->digests;
961 	} else {
962 		digests = PORT_ZAlloc(n_digest_params * sizeof (*digests));
963 		if (digests == NULL)
964 			cmsreterr(-1, cms, "could not allocate digest context");
965 	}
966 
967 	for (int i = 0; i < n_digest_params; i++) {
968 		digests[i].pk11ctx = PK11_CreateDigestContext(
969 						digest_params[i].digest_tag);
970 		if (!digests[i].pk11ctx) {
971 			cms->log(cms, LOG_ERR, "%s:%s:%d could not create "
972 				"digest context: %s",
973 				__FILE__, __func__, __LINE__,
974 				PORT_ErrorToString(PORT_GetError()));
975 			goto err;
976 		}
977 
978 		PK11_DigestBegin(digests[i].pk11ctx);
979 	}
980 
981 	cms->digests = digests;
982 	return 0;
983 
984 err:
985 	for (int i = 0; i < n_digest_params; i++) {
986 		if (digests[i].pk11ctx)
987 			PK11_DestroyContext(digests[i].pk11ctx, PR_TRUE);
988 	}
989 
990 	free(digests);
991 	return -1;
992 }
993 
994 void
generate_digest_step(cms_context * cms,void * data,size_t len)995 generate_digest_step(cms_context *cms, void *data, size_t len)
996 {
997 	for (int i = 0; i < n_digest_params; i++)
998 		PK11_DigestOp(cms->digests[i].pk11ctx, data, len);
999 }
1000 
1001 int
generate_digest_finish(cms_context * cms)1002 generate_digest_finish(cms_context *cms)
1003 {
1004 	void *mark = PORT_ArenaMark(cms->arena);
1005 
1006 	for (int i = 0; i < n_digest_params; i++) {
1007 		SECItem *digest = PORT_ArenaZAlloc(cms->arena,sizeof (SECItem));
1008 		if (digest == NULL) {
1009 			cms->log(cms, LOG_ERR, "%s:%s:%d could not allocate "
1010 				"memory: %s", __FILE__, __func__, __LINE__,
1011 				PORT_ErrorToString(PORT_GetError()));
1012 			goto err;
1013 		}
1014 
1015 		digest->type = siBuffer;
1016 		digest->len = digest_params[i].size;
1017 		digest->data = PORT_ArenaZAlloc(cms->arena, digest_params[i].size);
1018 		if (digest->data == NULL) {
1019 			cms->log(cms, LOG_ERR, "%s:%s:%d could not allocate "
1020 				"memory: %s", __FILE__, __func__, __LINE__,
1021 				PORT_ErrorToString(PORT_GetError()));
1022 			goto err;
1023 		}
1024 
1025 		PK11_DigestFinal(cms->digests[i].pk11ctx,
1026 			digest->data, &digest->len, digest_params[i].size);
1027 		PK11_Finalize(cms->digests[i].pk11ctx);
1028 		PK11_DestroyContext(cms->digests[i].pk11ctx, PR_TRUE);
1029 		cms->digests[i].pk11ctx = NULL;
1030 		/* XXX sure seems like we should be freeing it here,
1031 		 * but that's segfaulting, and we know it'll get
1032 		 * cleaned up with PORT_FreeArena a couple of lines
1033 		 * down.
1034 		 */
1035 		cms->digests[i].pe_digest = digest;
1036 	}
1037 
1038 	PORT_ArenaUnmark(cms->arena, mark);
1039 	return 0;
1040 err:
1041 	for (int i = 0; i < n_digest_params; i++) {
1042 		if (cms->digests[i].pk11ctx)
1043 			PK11_DestroyContext(cms->digests[i].pk11ctx, PR_TRUE);
1044 	}
1045 	PORT_ArenaRelease(cms->arena, mark);
1046 	return -1;
1047 }
1048 
1049 #if 1
1050 #define dprintf(fmt, ...)
1051 #else
1052 #define dprintf(fmt, args...) printf(fmt, ## args)
1053 #endif
1054 
1055 int
generate_digest(cms_context * cms,Pe * pe,int padded)1056 generate_digest(cms_context *cms, Pe *pe, int padded)
1057 {
1058 	void *hash_base;
1059 	size_t hash_size;
1060 	struct pe32_opt_hdr *pe32opthdr = NULL;
1061 	struct pe32plus_opt_hdr *pe64opthdr = NULL;
1062 	unsigned long hashed_bytes = 0;
1063 	int rc = -1;
1064 
1065 	if (!pe) {
1066 		cms->log(cms, LOG_ERR, "no output pe ready");
1067 		return -1;
1068 	}
1069 
1070 	rc = generate_digest_begin(cms);
1071 	if (rc < 0)
1072 		return rc;
1073 
1074 	struct pe_hdr pehdr;
1075 	if (pe_getpehdr(pe, &pehdr) == NULL)
1076 		pereterr(-1, "invalid PE file header");
1077 
1078 	void *map = NULL;
1079 	size_t map_size = 0;
1080 
1081 	/* 1. Load the image header into memory - should be done
1082 	 * 2. Initialize SHA hash context. */
1083 	map = pe_rawfile(pe, &map_size);
1084 	if (!map)
1085 		pereterr(-1, "could not get raw output file address");
1086 
1087 	/* 3. Calculate the distance from the base of the image header to the
1088 	 * image checksum.
1089 	 * 4. Hash the image header from start to the beginning of the
1090 	 * checksum. */
1091 	hash_base = map;
1092 	switch (pe_kind(pe)) {
1093 	case PE_K_PE_EXE: {
1094 		void *opthdr = pe_getopthdr(pe);
1095 		pe32opthdr = opthdr;
1096 		hash_size = (uintptr_t)&pe32opthdr->csum - (uintptr_t)hash_base;
1097 		break;
1098 	}
1099 	case PE_K_PE64_EXE: {
1100 		void *opthdr = pe_getopthdr(pe);
1101 		pe64opthdr = opthdr;
1102 		hash_size = (uintptr_t)&pe64opthdr->csum - (uintptr_t)hash_base;
1103 		break;
1104 	}
1105 	default:
1106 		goto error;
1107 	}
1108 	if (!check_pointer_and_size(pe, hash_base, hash_size)) {
1109 		cms->log(cms, LOG_ERR, "%s:%s:%d PE header is invalid",
1110 			__FILE__, __func__, __LINE__);
1111 		goto error;
1112 	}
1113 	dprintf("beginning of hash\n");
1114 	dprintf("digesting %lx + %lx\n", hash_base - map, hash_size);
1115 	generate_digest_step(cms, hash_base, hash_size);
1116 
1117 	/* 5. Skip over the image checksum
1118 	 * 6. Get the address of the beginning of the cert dir entry
1119 	 * 7. Hash from the end of the csum to the start of the cert dirent. */
1120 	hash_base += hash_size;
1121 	hash_base += pe32opthdr ? sizeof(pe32opthdr->csum)
1122 				: sizeof(pe64opthdr->csum);
1123 	data_directory *dd;
1124 
1125 	rc = pe_getdatadir(pe, &dd);
1126 	if (rc < 0 || !dd || !check_pointer_and_size(pe, dd, sizeof(*dd))) {
1127 		cms->log(cms, LOG_ERR, "%s:%s:%d PE data directory is invalid",
1128 			__FILE__, __func__, __LINE__);
1129 		goto error;
1130 	}
1131 
1132 	hash_size = (uintptr_t)&dd->certs - (uintptr_t)hash_base;
1133 	if (!check_pointer_and_size(pe, hash_base, hash_size)) {
1134 		cms->log(cms, LOG_ERR, "%s:%s:%d PE data directory is invalid",
1135 			__FILE__, __func__, __LINE__);
1136 		goto error;
1137 	}
1138 	generate_digest_step(cms, hash_base, hash_size);
1139 	dprintf("digesting %lx + %lx\n", hash_base - map, hash_size);
1140 
1141 	/* 8. Skip over the crt dir
1142 	 * 9. Hash everything up to the end of the image header. */
1143 	hash_base = &dd->base_relocations;
1144 	hash_size = (pe32opthdr ? pe32opthdr->header_size
1145 				: pe64opthdr->header_size) -
1146 		((uintptr_t)&dd->base_relocations - (uintptr_t)map);
1147 
1148 	if (!check_pointer_and_size(pe, hash_base, hash_size)) {
1149 		cms->log(cms, LOG_ERR, "%s:%s:%d PE relocations table is "
1150 			"invalid", __FILE__, __func__, __LINE__);
1151 		goto error;
1152 	}
1153 	generate_digest_step(cms, hash_base, hash_size);
1154 	dprintf("digesting %lx + %lx\n", hash_base - map, hash_size);
1155 
1156 	/* 10. Set SUM_OF_BYTES_HASHED to the size of the header. */
1157 	hashed_bytes = pe32opthdr ? pe32opthdr->header_size
1158 				: pe64opthdr->header_size;
1159 
1160 	struct section_header *shdrs = calloc(pehdr.sections, sizeof (*shdrs));
1161 	if (!shdrs)
1162 		goto error;
1163 	Pe_Scn *scn = NULL;
1164 	for (int i = 0; i < pehdr.sections; i++) {
1165 		scn = pe_nextscn(pe, scn);
1166 		if (scn == NULL)
1167 			break;
1168 		pe_getshdr(scn, &shdrs[i]);
1169 	}
1170 	sort_shdrs(shdrs, pehdr.sections - 1);
1171 
1172 	for (int i = 0; i < pehdr.sections; i++) {
1173 		if (shdrs[i].raw_data_size == 0)
1174 			continue;
1175 
1176 		hash_base = (void *)((uintptr_t)map + shdrs[i].data_addr);
1177 		hash_size = shdrs[i].raw_data_size;
1178 
1179 		if (!check_pointer_and_size(pe, hash_base, hash_size)) {
1180 			cms->log(cms, LOG_ERR, "%s:%s:%d PE section \"%s\" "
1181 				"has invalid address",
1182 				__FILE__, __func__, __LINE__, shdrs[i].name);
1183 			goto error_shdrs;
1184 		}
1185 
1186 		generate_digest_step(cms, hash_base, hash_size);
1187 		dprintf("digesting %lx + %lx\n", hash_base - map, hash_size);
1188 
1189 		hashed_bytes += hash_size;
1190 	}
1191 
1192 	if (map_size > hashed_bytes) {
1193 		hash_base = (void *)((uintptr_t)map + hashed_bytes);
1194 		hash_size = map_size - dd->certs.size - hashed_bytes;
1195 
1196 		if (!check_pointer_and_size(pe, hash_base, hash_size)) {
1197 			cms->log(cms, LOG_ERR, "%s:%s:%d PE has invalid "
1198 				"trailing data", __FILE__, __func__, __LINE__);
1199 			goto error_shdrs;
1200 		}
1201 		if (hash_size % 8 != 0 && padded) {
1202 			size_t tmp_size = hash_size +
1203 					  ALIGNMENT_PADDING(hash_size, 8);
1204 			uint8_t tmp_array[tmp_size];
1205 			memset(tmp_array, '\0', tmp_size);
1206 			memcpy(tmp_array, hash_base, hash_size);
1207 			generate_digest_step(cms, tmp_array, tmp_size);
1208 			dprintf("digesting %lx + %lx\n", (unsigned long)tmp_array, tmp_size);
1209 		} else {
1210 			generate_digest_step(cms, hash_base, hash_size);
1211 			dprintf("digesting %lx + %lx\n", hash_base - map, hash_size);
1212 		}
1213 	}
1214 	dprintf("end of hash\n");
1215 
1216 	rc = generate_digest_finish(cms);
1217 	if (rc < 0)
1218 		goto error_shdrs;
1219 
1220 	if (shdrs) {
1221 		free(shdrs);
1222 		shdrs = NULL;
1223 	}
1224 
1225 	return 0;
1226 
1227 error_shdrs:
1228 	if (shdrs)
1229 		free(shdrs);
1230 error:
1231 	return -1;
1232 }
1233 
1234 /* before you run this, you'll need to enroll your CA with:
1235  * certutil -A -n 'my CA' -d /etc/pki/pesign -t CT,CT,CT -i ca.crt
1236  * And you'll need to enroll the private key like this:
1237  * pk12util -d /etc/pki/pesign/ -i Peter\ Jones.p12
1238  */
1239 int
generate_signature(cms_context * cms)1240 generate_signature(cms_context *cms)
1241 {
1242 	int rc = 0;
1243 
1244 	if (cms->digests[cms->selected_digest].pe_digest == NULL) {
1245 		cms->log(cms, LOG_ERR, "%s:%s:%d PE digest has not been "
1246 			"allocated", __FILE__, __func__, __LINE__);
1247 		return -1;
1248 	}
1249 
1250 	if (content_is_empty(cms->digests[cms->selected_digest].pe_digest->data,
1251 			cms->digests[cms->selected_digest].pe_digest->len)) {
1252 		cms->log(cms, LOG_ERR, "%s:%s:%d PE binary has not been "
1253 			"digested", __FILE__, __func__, __LINE__);
1254 		return -1;
1255 	}
1256 
1257 	SECItem sd_der;
1258 	memset(&sd_der, '\0', sizeof(sd_der));
1259 	rc = generate_spc_signed_data(cms, &sd_der);
1260 	if (rc < 0)
1261 		cmsreterr(-1, cms, "could not create signed data");
1262 
1263 	memcpy(&cms->newsig, &sd_der, sizeof (cms->newsig));
1264 	cms->newsig.data = malloc(sd_der.len);
1265 	if (!cms->newsig.data)
1266 		cmsreterr(-1, cms, "could not allocate signed data");
1267 	memcpy(cms->newsig.data, sd_der.data, sd_der.len);
1268 	return 0;
1269 }
1270 
1271 typedef struct {
1272 	SECItem start;
1273 	SECItem end;
1274 } Validity;
1275 
1276 static SEC_ASN1Template ValidityTemplate[] = {
1277 	{.kind = SEC_ASN1_SEQUENCE,
1278 	 .offset = 0,
1279 	 .sub = NULL,
1280 	 .size = sizeof (Validity),
1281 	},
1282 	{.kind = SEC_ASN1_ANY,
1283 	 .offset = offsetof(Validity, start),
1284 	 .sub = &SEC_AnyTemplate,
1285 	 .size = sizeof (SECItem),
1286 	},
1287 	{.kind = SEC_ASN1_ANY,
1288 	 .offset = offsetof(Validity, end),
1289 	 .sub = &SEC_AnyTemplate,
1290 	 .size = sizeof (SECItem),
1291 	},
1292 	{ 0 }
1293 };
1294 
1295 int
generate_validity(cms_context * cms,SECItem * der,time_t start,time_t end)1296 generate_validity(cms_context *cms, SECItem *der, time_t start, time_t end)
1297 {
1298 	Validity validity;
1299 	int rc;
1300 
1301 	rc = generate_time(cms, &validity.start, start);
1302 	if (rc < 0)
1303 		return rc;
1304 
1305 	rc = generate_time(cms, &validity.end, end);
1306 	if (rc < 0)
1307 		return rc;
1308 
1309 	void *ret;
1310 	ret = SEC_ASN1EncodeItem(cms->arena, der, &validity, ValidityTemplate);
1311 	if (ret == NULL)
1312 		cmsreterr(-1, cms, "could not encode validity");
1313 	return 0;
1314 }
1315 
1316 static SEC_ASN1Template SetTemplate = {
1317 	.kind = SEC_ASN1_SET_OF,
1318 	.offset = 0,
1319 	.sub = &SEC_AnyTemplate,
1320 	.size = sizeof (SECItem **)
1321 	};
1322 
1323 int
wrap_in_set(cms_context * cms,SECItem * der,SECItem ** items)1324 wrap_in_set(cms_context *cms, SECItem *der, SECItem **items)
1325 {
1326 	void *ret;
1327 
1328 	ret = SEC_ASN1EncodeItem(cms->arena, der, &items, &SetTemplate);
1329 	if (ret == NULL)
1330 		cmsreterr(-1, cms, "could not encode set");
1331 	return 0;
1332 }
1333 
1334 static SEC_ASN1Template SeqTemplateTemplate = {
1335 	.kind = SEC_ASN1_ANY,
1336 	.offset = 0,
1337 	.sub = &SEC_AnyTemplate,
1338 	.size = sizeof (SECItem),
1339 	};
1340 
1341 static SEC_ASN1Template SeqTemplateHeader = {
1342 	.kind = SEC_ASN1_SEQUENCE,
1343 	.offset = 0,
1344 	.sub = NULL,
1345 	.size = sizeof (SECItem)
1346 	};
1347 
1348 int
wrap_in_seq(cms_context * cms,SECItem * der,SECItem * items,int num_items)1349 wrap_in_seq(cms_context *cms, SECItem *der, SECItem *items, int num_items)
1350 {
1351 	void *ret;
1352 
1353 	void *mark = PORT_ArenaMark(cms->arena);
1354 
1355 	SEC_ASN1Template tmpl[num_items+2];
1356 
1357 	memcpy(&tmpl[0], &SeqTemplateHeader, sizeof(*tmpl));
1358 	tmpl[0].size = sizeof (SECItem) * num_items;
1359 
1360 	for (int i = 0; i < num_items; i++) {
1361 		memcpy(&tmpl[i+1], &SeqTemplateTemplate, sizeof(SEC_ASN1Template));
1362 		tmpl[i+1].offset = (i) * sizeof (SECItem);
1363 	}
1364 	memset(&tmpl[num_items + 1], '\0', sizeof(SEC_ASN1Template));
1365 
1366 	int rc = 0;
1367 	ret = SEC_ASN1EncodeItem(cms->arena, der, items, tmpl);
1368 	if (ret == NULL) {
1369 		save_port_err(PORT_ArenaRelease(cms->arena, mark));
1370 		cmsreterr(-1, cms, "could not encode set");
1371 	}
1372 	PORT_ArenaUnmark(cms->arena, mark);
1373 	return rc;
1374 }
1375 
1376 typedef struct {
1377 	SECItem oid;
1378 	SECItem string;
1379 } CommonName;
1380 
1381 static SEC_ASN1Template CommonNameTemplate[] = {
1382 	{.kind = SEC_ASN1_SEQUENCE,
1383 	 .offset = 0,
1384 	 .sub = NULL,
1385 	 .size = sizeof (CommonName),
1386 	},
1387 	{.kind = SEC_ASN1_ANY,
1388 	 .offset = offsetof(CommonName, oid),
1389 	 .sub = &SEC_AnyTemplate,
1390 	 .size = sizeof (SECItem),
1391 	},
1392 	{.kind = SEC_ASN1_ANY,
1393 	 .offset = offsetof(CommonName, string),
1394 	 .sub = &SEC_AnyTemplate,
1395 	 .size = sizeof (SECItem),
1396 	},
1397 	{ 0 }
1398 };
1399 
1400 int
generate_common_name(cms_context * cms,SECItem * der,char * cn_str)1401 generate_common_name(cms_context *cms, SECItem *der, char *cn_str)
1402 {
1403 	CommonName cn;
1404 	SECItem cn_item;
1405 	int rc;
1406 
1407 	rc = generate_object_id(cms, &cn.oid, SEC_OID_AVA_COMMON_NAME);
1408 	if (rc < 0)
1409 		return rc;
1410 	rc = generate_string(cms, &cn.string, cn_str);
1411 	if (rc < 0)
1412 		return rc;
1413 
1414 	void *ret;
1415 	ret = SEC_ASN1EncodeItem(cms->arena, &cn_item, &cn, CommonNameTemplate);
1416 	if (ret == NULL)
1417 		cmsreterr(-1, cms, "could not encode common name");
1418 
1419 	SECItem cn_set;
1420 	SECItem *items[2] = {&cn_item, NULL};
1421 	rc = wrap_in_set(cms, &cn_set, items);
1422 	if (rc < 0)
1423 		return rc;
1424 	rc = wrap_in_seq(cms, der, &cn_set, 1);
1425 	if (rc < 0)
1426 		return rc;
1427 	return 0;
1428 }
1429 
1430 typedef struct {
1431 	SECItem type;
1432 	SECItem value;
1433 } ava;
1434 
1435 static const SEC_ASN1Template AVATemplate[] = {
1436 	{.kind = SEC_ASN1_SEQUENCE,
1437 	 .offset = 0,
1438 	 .sub = NULL,
1439 	 .size = sizeof (ava),
1440 	},
1441 	{.kind = SEC_ASN1_ANY,
1442 	 .offset = offsetof(ava, type),
1443 	 .sub = &SEC_AnyTemplate,
1444 	 .size = sizeof (SECItem),
1445 	},
1446 	{.kind = SEC_ASN1_ANY,
1447 	 .offset = offsetof(ava, value),
1448 	 .sub = &SEC_AnyTemplate,
1449 	 .size = sizeof (SECItem),
1450 	},
1451 	{ 0 }
1452 };
1453 
1454 /* I can't figure out how to get a CERTName out in a non-rediculous form, so
1455  * we wind up encoding the whole thing manually :/ */
1456 static int
generate_ava(cms_context * cms,SECItem * der,CERTAVA * certava)1457 generate_ava(cms_context *cms, SECItem *der, CERTAVA *certava)
1458 {
1459 	ava ava;
1460 
1461 	SECOidData *oid;
1462 
1463 	void *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1464 	if (arena == NULL)
1465 		cmsreterr(-1, cms, "could not create arena");
1466 
1467 	void *real_arena = cms->arena;
1468 	cms->arena = arena;
1469 
1470 	oid = SECOID_FindOID(&certava->type);
1471 	if (!oid) {
1472 		save_port_err(PORT_FreeArena(arena, PR_TRUE));
1473 		cms->arena = real_arena;
1474 		cmsreterr(-1, cms, "could not find OID");
1475 	}
1476 
1477 	int rc = generate_object_id(cms, &ava.type, oid->offset);
1478 	if (rc < 0) {
1479 		PORT_FreeArena(arena, PR_TRUE);
1480 		cms->arena = real_arena;
1481 		return -1;
1482 	}
1483 
1484 	memcpy(&ava.value, &certava->value, sizeof (ava.value));
1485 
1486 	void *ret;
1487 	SECItem tmp;
1488 	ret = SEC_ASN1EncodeItem(arena, &tmp, &ava, AVATemplate);
1489 	if (ret == NULL) {
1490 		save_port_err(PORT_FreeArena(arena, PR_TRUE));
1491 		cms->arena = real_arena;
1492 		cmsreterr(-1, cms, "could not encode AVA");
1493 	}
1494 
1495 	der->type = tmp.type;
1496 	der->len = tmp.len;
1497 	der->data = PORT_ArenaAlloc(real_arena, tmp.len);
1498 	if (!der->data) {
1499 		save_port_err(PORT_FreeArena(arena, PR_TRUE));
1500 		cms->arena = real_arena;
1501 		cmsreterr(-1, cms, "could not allocate AVA");
1502 	}
1503 	memcpy(der->data, tmp.data, tmp.len);
1504 	PORT_FreeArena(arena, PR_TRUE);
1505 	cms->arena = real_arena;
1506 
1507 	return 0;
1508 }
1509 
1510 int
generate_name(cms_context * cms,SECItem * der,CERTName * certname)1511 generate_name(cms_context *cms, SECItem *der, CERTName *certname)
1512 {
1513 	void *marka = PORT_ArenaMark(cms->arena);
1514 	CERTRDN **rdns = certname->rdns;
1515 	CERTRDN *rdn;
1516 
1517 	int num_items = 0;
1518 	int rc = 0;
1519 
1520 	while (rdns && (rdn = *rdns++) != NULL) {
1521 		CERTAVA **avas = rdn->avas;
1522 		CERTAVA *ava;
1523 		while (avas && (ava = *avas++) != NULL)
1524 			num_items++;
1525 	}
1526 
1527 	SECItem items[num_items];
1528 
1529 	int i = 0;
1530 	rdns = certname->rdns;
1531 	while (rdns && (rdn = *rdns++) != NULL) {
1532 		CERTAVA **avas = rdn->avas;
1533 		CERTAVA *ava;
1534 		while (avas && (ava = *avas++) != NULL) {
1535 			SECItem avader;
1536 			rc = generate_ava(cms, &avader, ava);
1537 			if (rc < 0) {
1538 				PORT_ArenaRelease(cms->arena, marka);
1539 				return -1;
1540 			}
1541 
1542 			SECItem *list[2] = {
1543 				&avader,
1544 				NULL,
1545 			};
1546 			rc = wrap_in_set(cms, &items[i], list);
1547 			if (rc < 0) {
1548 				PORT_ArenaRelease(cms->arena, marka);
1549 				return -1;
1550 			}
1551 			i++;
1552 		}
1553 	}
1554 	wrap_in_seq(cms, der, &items[0], num_items);
1555 	PORT_ArenaUnmark(cms->arena, marka);
1556 
1557 	return 0;
1558 }
1559 
1560 typedef struct {
1561 	SECItem oid;
1562 	SECItem url;
1563 } AuthInfo;
1564 
1565 static SEC_ASN1Template AuthInfoTemplate[] = {
1566 	{.kind = SEC_ASN1_SEQUENCE,
1567 	 .offset = 0,
1568 	 .sub = NULL,
1569 	 .size = sizeof (AuthInfo),
1570 	},
1571 	{.kind = SEC_ASN1_OBJECT_ID,
1572 	 .offset = offsetof(AuthInfo, oid),
1573 	 .sub = &SEC_ObjectIDTemplate,
1574 	 .size = sizeof (SECItem),
1575 	},
1576 	{.kind = SEC_ASN1_ANY,
1577 	 .offset = offsetof(AuthInfo, url),
1578 	 .sub = &SEC_AnyTemplate,
1579 	 .size = sizeof (SECItem),
1580 	},
1581 	{ 0 }
1582 };
1583 
1584 static SEC_ASN1Template AuthInfoWrapperTemplate[] = {
1585 	{.kind = SEC_ASN1_SEQUENCE,
1586 	 .offset = 0,
1587 	 .sub = NULL,
1588 	 .size = sizeof (AuthInfo),
1589 	},
1590 	{.kind = SEC_ASN1_OBJECT_ID,
1591 	 .offset = offsetof(AuthInfo, oid),
1592 	 .sub = &SEC_ObjectIDTemplate,
1593 	 .size = sizeof (SECItem),
1594 	},
1595 	{.kind = SEC_ASN1_ANY,
1596 	 .offset = offsetof(AuthInfo, url),
1597 	 .sub = &SEC_AnyTemplate,
1598 	 .size = sizeof (SECItem),
1599 	},
1600 	{ 0 }
1601 };
1602 
1603 int
generate_auth_info(cms_context * cms,SECItem * der,char * url)1604 generate_auth_info(cms_context *cms, SECItem *der, char *url)
1605 {
1606 	AuthInfo ai;
1607 
1608 	SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CA_ISSUERS);
1609 	if (!oid)
1610 		cmsreterr(-1, cms, "could not get CA issuers OID");
1611 
1612 	memcpy(&ai.oid, &oid->oid, sizeof (ai.oid));
1613 
1614 	SECItem urlitem = {
1615 		.data = (unsigned char *)url,
1616 		.len = strlen(url),
1617 		.type = siBuffer
1618 	};
1619 	int rc = make_context_specific(cms, 6, &ai.url, &urlitem);
1620 	if (rc < 0)
1621 		return rc;
1622 
1623 	void *ret;
1624 	SECItem unwrapped;
1625 	ret = SEC_ASN1EncodeItem(cms->arena, &unwrapped, &ai, AuthInfoTemplate);
1626 	if (ret == NULL)
1627 		cmsreterr(-1, cms, "could not encode CA Issuers");
1628 
1629 	rc = wrap_in_seq(cms, der, &unwrapped, 1);
1630 	if (rc < 0)
1631 		return rc;
1632 	return 0;
1633 
1634 	/* I've no idea how to get SEC_ASN1EncodeItem to spit out the thing
1635 	 * we actually want here.  So once again, just force the data to
1636 	 * look correct :( */
1637 	if (unwrapped.len < 12) {
1638 		cms->log(cms, LOG_ERR, "%s:%s:%d generated CA Issuers Info "
1639 			"cannot possibly be valid",
1640 			__FILE__, __func__, __LINE__);
1641 		return -1;
1642 	}
1643 	unwrapped.data[12] = 0x86;
1644 	unwrapped.type = siBuffer;
1645 
1646 	AuthInfo wrapper;
1647 	oid = SECOID_FindOIDByTag(SEC_OID_X509_AUTH_INFO_ACCESS);
1648 	if (!oid)
1649 		cmsreterr(-1, cms, "could not find Auth Info Access OID");
1650 
1651 	memcpy(&wrapper.oid, &oid->oid, sizeof (ai.oid));
1652 
1653 	wrap_in_seq(cms, &wrapper.url, &unwrapped, 1);
1654 
1655 	ret = SEC_ASN1EncodeItem(cms->arena, der, &wrapper,
1656 					AuthInfoWrapperTemplate);
1657 	if (ret == NULL)
1658 		cmsreterr(-1, cms, "could not encode CA Issuers OID");
1659 
1660 	return 0;
1661 }
1662 
1663 typedef struct {
1664 	SECItem oid;
1665 	SECItem keyhash;
1666 } KeyId;
1667 
1668 int
generate_keys(cms_context * cms,PK11SlotInfo * slot,SECKEYPrivateKey ** privkey,SECKEYPublicKey ** pubkey)1669 generate_keys(cms_context *cms, PK11SlotInfo *slot,
1670 		SECKEYPrivateKey **privkey, SECKEYPublicKey **pubkey)
1671 {
1672 	PK11RSAGenParams rsaparams = {
1673 		.keySizeInBits = 2048,
1674 		.pe = 0x010001,
1675 	};
1676 
1677 	SECStatus rv;
1678 	rv = PK11_Authenticate(slot, PR_TRUE, cms->pwdata);
1679 	if (rv != SECSuccess)
1680 		cmsreterr(-1, cms, "could not authenticate with pk11 service");
1681 
1682 	void *params = &rsaparams;
1683 	*privkey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
1684 					params, pubkey, PR_TRUE, PR_TRUE,
1685 					cms->pwdata);
1686 	if (!*privkey)
1687 		cmsreterr(-1, cms, "could not generate RSA keypair");
1688 	return 0;
1689 }
1690