File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / pki / commands / pkcs7.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 09:46:44 2020 UTC (4 years, 3 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, v5_8_4p7, HEAD
Strongswan

    1: /*
    2:  * Copyright (C) 2012 Martin Willi
    3:  * Copyright (C) 2012 revosec AG
    4:  *
    5:  * This program is free software; you can redistribute it and/or modify it
    6:  * under the terms of the GNU General Public License as published by the
    7:  * Free Software Foundation; either version 2 of the License, or (at your
    8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
    9:  *
   10:  * This program is distributed in the hope that it will be useful, but
   11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   13:  * for more details.
   14:  */
   15: 
   16: #include "pki.h"
   17: 
   18: #include <asn1/oid.h>
   19: #include <asn1/asn1.h>
   20: #include <credentials/containers/pkcs7.h>
   21: #include <credentials/sets/mem_cred.h>
   22: 
   23: /**
   24:  * Read input data as chunk
   25:  */
   26: static chunk_t read_from_stream(FILE *stream)
   27: {
   28: 	char buf[8096];
   29: 	size_t len, total = 0;
   30: 
   31: 	while (TRUE)
   32: 	{
   33: 		len = fread(buf + total, 1, sizeof(buf) - total, stream);
   34: 		if (len < (sizeof(buf) - total))
   35: 		{
   36: 			if (ferror(stream))
   37: 			{
   38: 				return chunk_empty;
   39: 			}
   40: 			if (feof(stream))
   41: 			{
   42: 				return chunk_clone(chunk_create(buf, total + len));
   43: 			}
   44: 		}
   45: 		total += len;
   46: 		if (total == sizeof(buf))
   47: 		{
   48: 			fprintf(stderr, "buffer too small to read input!\n");
   49: 			return chunk_empty;
   50: 		}
   51: 	}
   52: }
   53: 
   54: /**
   55:  * Write output data from chunk to stream
   56:  */
   57: static bool write_to_stream(FILE *stream, chunk_t data)
   58: {
   59: 	size_t len, total = 0;
   60: 
   61: 	set_file_mode(stream, CERT_ASN1_DER);
   62: 	while (total < data.len)
   63: 	{
   64: 		len = fwrite(data.ptr + total, 1, data.len - total, stream);
   65: 		if (len <= 0)
   66: 		{
   67: 			return FALSE;
   68: 		}
   69: 		total += len;
   70: 	}
   71: 	return TRUE;
   72: }
   73: 
   74: /**
   75:  * Verify PKCS#7 signed-data
   76:  */
   77: static int verify(chunk_t chunk)
   78: {
   79: 	container_t *container;
   80: 	pkcs7_t *pkcs7;
   81: 	enumerator_t *enumerator;
   82: 	certificate_t *cert;
   83: 	auth_cfg_t *auth;
   84: 	chunk_t data;
   85: 	time_t t;
   86: 	bool verified = FALSE;
   87: 
   88: 	container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7,
   89: 								   BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
   90: 	if (!container)
   91: 	{
   92: 		return 1;
   93: 	}
   94: 
   95: 	if (container->get_type(container) != CONTAINER_PKCS7_SIGNED_DATA)
   96: 	{
   97: 		fprintf(stderr, "verification failed, container is %N\n",
   98: 				container_type_names, container->get_type(container));
   99: 		container->destroy(container);
  100: 		return 1;
  101: 	}
  102: 
  103: 	pkcs7 = (pkcs7_t*)container;
  104: 	enumerator = container->create_signature_enumerator(container);
  105: 	while (enumerator->enumerate(enumerator, &auth))
  106: 	{
  107: 		verified = TRUE;
  108: 		cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
  109: 		if (cert)
  110: 		{
  111: 			fprintf(stderr, "signed by '%Y'", cert->get_subject(cert));
  112: 
  113: 			if (pkcs7->get_attribute(pkcs7, OID_PKCS9_SIGNING_TIME,
  114: 									 enumerator, &data))
  115: 			{
  116: 				t = asn1_to_time(&data, ASN1_UTCTIME);
  117: 				if (t != UNDEFINED_TIME)
  118: 				{
  119: 					fprintf(stderr, " at %T", &t, FALSE);
  120: 				}
  121: 				free(data.ptr);
  122: 			}
  123: 			fprintf(stderr, "\n");
  124: 		}
  125: 	}
  126: 	enumerator->destroy(enumerator);
  127: 
  128: 	if (!verified)
  129: 	{
  130: 		fprintf(stderr, "no trusted signature found\n");
  131: 	}
  132: 
  133: 	if (verified)
  134: 	{
  135: 		if (container->get_data(container, &data))
  136: 		{
  137: 			write_to_stream(stdout, data);
  138: 			free(data.ptr);
  139: 		}
  140: 		else
  141: 		{
  142: 			verified = FALSE;
  143: 		}
  144: 	}
  145: 	container->destroy(container);
  146: 
  147: 	return verified ? 0 : 1;
  148: }
  149: 
  150: /**
  151:  * Sign data into PKCS#7 signed-data
  152:  */
  153: static int sign(chunk_t chunk, certificate_t *cert, private_key_t *key)
  154: {
  155: 	container_t *container;
  156: 	chunk_t encoding;
  157: 	int res = 1;
  158: 
  159: 	container = lib->creds->create(lib->creds,
  160: 								   CRED_CONTAINER, CONTAINER_PKCS7_SIGNED_DATA,
  161: 								   BUILD_BLOB, chunk,
  162: 								   BUILD_SIGNING_CERT, cert,
  163: 								   BUILD_SIGNING_KEY, key,
  164: 								   BUILD_END);
  165: 	if (container)
  166: 	{
  167: 		if (container->get_encoding(container, &encoding))
  168: 		{
  169: 			write_to_stream(stdout, encoding);
  170: 			free(encoding.ptr);
  171: 		}
  172: 		container->destroy(container);
  173: 	}
  174: 	return res;
  175: }
  176: 
  177: /**
  178:  * Encrypt data to a PKCS#7 enveloped-data
  179:  */
  180: static int encrypt(chunk_t chunk, certificate_t *cert)
  181: {
  182: 	container_t *container;
  183: 	chunk_t encoding;
  184: 	int res = 1;
  185: 
  186: 	container = lib->creds->create(lib->creds,
  187: 								   CRED_CONTAINER, CONTAINER_PKCS7_ENVELOPED_DATA,
  188: 								   BUILD_BLOB, chunk, BUILD_CERT, cert,
  189: 								   BUILD_END);
  190: 	if (container)
  191: 	{
  192: 		if (container->get_encoding(container, &encoding))
  193: 		{
  194: 			write_to_stream(stdout, encoding);
  195: 			free(encoding.ptr);
  196: 		}
  197: 		container->destroy(container);
  198: 	}
  199: 	return res;
  200: }
  201: 
  202: /**
  203:  * Decrypt PKCS#7 enveloped-data
  204:  */
  205: static int decrypt(chunk_t chunk)
  206: {
  207: 	container_t *container;
  208: 	chunk_t data;
  209: 
  210: 	container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7,
  211: 								   BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
  212: 	if (!container)
  213: 	{
  214: 		return 1;
  215: 	}
  216: 	if (container->get_type(container) != CONTAINER_PKCS7_ENVELOPED_DATA)
  217: 	{
  218: 		fprintf(stderr, "decryption failed, container is %N\n",
  219: 				container_type_names, container->get_type(container));
  220: 		container->destroy(container);
  221: 		return 1;
  222: 	}
  223: 	if (!container->get_data(container, &data))
  224: 	{
  225: 		fprintf(stderr, "PKCS#7 decryption failed\n");
  226: 		container->destroy(container);
  227: 		return 1;
  228: 	}
  229: 	container->destroy(container);
  230: 
  231: 	write_to_stream(stdout, data);
  232: 	free(data.ptr);
  233: 
  234: 	return 0;
  235: }
  236: 
  237: /**
  238:  * Show info about PKCS#7 container
  239:  */
  240: static int show(chunk_t chunk)
  241: {
  242: 	container_t *container;
  243: 	pkcs7_t *pkcs7;
  244: 	enumerator_t *enumerator;
  245: 	certificate_t *cert;
  246: 	chunk_t data;
  247: 
  248: 	container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7,
  249: 								   BUILD_BLOB_ASN1_DER, chunk, BUILD_END);
  250: 	if (!container)
  251: 	{
  252: 		return 1;
  253: 	}
  254: 	fprintf(stderr, "%N\n", container_type_names, container->get_type(container));
  255: 
  256: 	if (container->get_type(container) == CONTAINER_PKCS7_SIGNED_DATA)
  257: 	{
  258: 		pkcs7 = (pkcs7_t*)container;
  259: 		enumerator = pkcs7->create_cert_enumerator(pkcs7);
  260: 		while (enumerator->enumerate(enumerator, &cert))
  261: 		{
  262: 			if (cert->get_encoding(cert, CERT_PEM, &data))
  263: 			{
  264: 				printf("%.*s", (int)data.len, data.ptr);
  265: 				free(data.ptr);
  266: 			}
  267: 		}
  268: 		enumerator->destroy(enumerator);
  269: 	}
  270: 	container->destroy(container);
  271: 	return 0;
  272: }
  273: 
  274: /**
  275:  * Wrap/Unwrap PKCs#7 containers
  276:  */
  277: static int pkcs7()
  278: {
  279: 	char *arg, *file = NULL;
  280: 	private_key_t *key = NULL;
  281: 	certificate_t *cert = NULL;
  282: 	chunk_t data = chunk_empty;
  283: 	mem_cred_t *creds;
  284: 	int res = 1;
  285: 	FILE *in;
  286: 	enum {
  287: 		OP_NONE,
  288: 		OP_SIGN,
  289: 		OP_VERIFY,
  290: 		OP_ENCRYPT,
  291: 		OP_DECRYPT,
  292: 		OP_SHOW,
  293: 	} op = OP_NONE;
  294: 
  295: 	creds = mem_cred_create();
  296: 
  297: 	while (TRUE)
  298: 	{
  299: 		switch (command_getopt(&arg))
  300: 		{
  301: 			case 'h':
  302: 				creds->destroy(creds);
  303: 				return command_usage(NULL);
  304: 			case 'i':
  305: 				file = arg;
  306: 				continue;
  307: 			case 's':
  308: 				if (op != OP_NONE)
  309: 				{
  310: 					goto invalid;
  311: 				}
  312: 				op = OP_SIGN;
  313: 				continue;
  314: 			case 'u':
  315: 				if (op != OP_NONE)
  316: 				{
  317: 					goto invalid;
  318: 				}
  319: 				op = OP_VERIFY;
  320: 				continue;
  321: 			case 'e':
  322: 				if (op != OP_NONE)
  323: 				{
  324: 					goto invalid;
  325: 				}
  326: 				op = OP_ENCRYPT;
  327: 				continue;
  328: 			case 'd':
  329: 				if (op != OP_NONE)
  330: 				{
  331: 					goto invalid;
  332: 				}
  333: 				op = OP_DECRYPT;
  334: 				continue;
  335: 			case 'p':
  336: 				if (op != OP_NONE)
  337: 				{
  338: 					goto invalid;
  339: 				}
  340: 				op = OP_SHOW;
  341: 				continue;
  342: 			case 'k':
  343: 				key = lib->creds->create(lib->creds,
  344: 										 CRED_PRIVATE_KEY, KEY_RSA,
  345: 										 BUILD_FROM_FILE, arg, BUILD_END);
  346: 				if (!key)
  347: 				{
  348: 					fprintf(stderr, "parsing private key failed\n");
  349: 					goto end;
  350: 				}
  351: 				creds->add_key(creds, key);
  352: 				continue;
  353: 			case 'c':
  354: 				cert = lib->creds->create(lib->creds,
  355: 										  CRED_CERTIFICATE, CERT_X509,
  356: 										  BUILD_FROM_FILE, arg, BUILD_END);
  357: 				if (!cert)
  358: 				{
  359: 					fprintf(stderr, "parsing certificate failed\n");
  360: 					goto end;
  361: 				}
  362: 				creds->add_cert(creds, TRUE, cert);
  363: 				continue;
  364: 			case EOF:
  365: 				break;
  366: 			default:
  367: 			invalid:
  368: 				creds->destroy(creds);
  369: 				return command_usage("invalid --pkcs7 option");
  370: 		}
  371: 		break;
  372: 	}
  373: 
  374: 	if (file)
  375: 	{
  376: 		in = fopen(file, "r");
  377: 		if (in)
  378: 		{
  379: 			data = read_from_stream(in);
  380: 			fclose(in);
  381: 		}
  382: 	}
  383: 	else
  384: 	{
  385: 		data = read_from_stream(stdin);
  386: 	}
  387: 
  388: 	if (!data.len)
  389: 	{
  390: 		fprintf(stderr, "reading input failed!\n");
  391: 		goto end;
  392: 	}
  393: 	if (op != OP_SHOW && !cert)
  394: 	{
  395: 		fprintf(stderr, "requiring a certificate!\n");
  396: 		goto end;
  397: 	}
  398: 
  399: 	lib->credmgr->add_local_set(lib->credmgr, &creds->set, FALSE);
  400: 
  401: 	switch (op)
  402: 	{
  403: 		case OP_SIGN:
  404: 			if (!key)
  405: 			{
  406: 				fprintf(stderr, "signing requires a private key\n");
  407: 				res = 1;
  408: 				break;
  409: 			}
  410: 			res = sign(data, cert, key);
  411: 			break;
  412: 		case OP_VERIFY:
  413: 			res = verify(data);
  414: 			break;
  415: 		case OP_ENCRYPT:
  416: 			res = encrypt(data, cert);
  417: 			break;
  418: 		case OP_DECRYPT:
  419: 			if (!key)
  420: 			{
  421: 				fprintf(stderr, "decryption requires a private key\n");
  422: 				res = 1;
  423: 				break;
  424: 			}
  425: 			res = decrypt(data);
  426: 			break;
  427: 		case OP_SHOW:
  428: 			res = show(data);
  429: 			break;
  430: 		default:
  431: 			res = 1;
  432: 			break;
  433: 	}
  434: 	lib->credmgr->remove_local_set(lib->credmgr, &creds->set);
  435: 
  436: end:
  437: 	creds->destroy(creds);
  438: 	free(data.ptr);
  439: 	return res;
  440: }
  441: 
  442: /**
  443:  * Register the command.
  444:  */
  445: static void __attribute__ ((constructor))reg()
  446: {
  447: 	command_register((command_t) {
  448: 		pkcs7, '7', "pkcs7", "PKCS#7 wrap/unwrap functions",
  449: 		{"--sign|--verify|--encrypt|--decrypt|--show",
  450: 		 "[--in file] [--cert file]+ [--key file]"},
  451: 		{
  452: 			{"help",	'h', 0, "show usage information"},
  453: 			{"sign",	's', 0, "create PKCS#7 signed-data"},
  454: 			{"verify",	'u', 0, "verify PKCS#7 signed-data"},
  455: 			{"encrypt",	'e', 0, "create PKCS#7 enveloped-data"},
  456: 			{"decrypt",	'd', 0, "decrypt PKCS#7 enveloped-data"},
  457: 			{"show",	'p', 0, "show info about PKCS#7, print certificates"},
  458: 			{"in",		'i', 1, "input file, default: stdin"},
  459: 			{"key",		'k', 1, "path to private key for sign/decrypt"},
  460: 			{"cert",	'c', 1, "path to certificate for sign/verify/encrypt"},
  461: 		}
  462: 	});
  463: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>