2 * Copyright (C) 2012 Martin Willi
3 * Copyright (C) 2012 revosec AG
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>.
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
19 #include <asn1/asn1.h>
20 #include <credentials/containers/pkcs7.h>
21 #include <credentials/sets/mem_cred.h>
24 * Read input data as chunk
26 static chunk_t
read_from_stream(FILE *stream
)
29 size_t len
, total
= 0;
33 len
= fread(buf
+ total
, 1, sizeof(buf
) - total
, stream
);
40 return chunk_clone(chunk_create(buf
, total
));
43 if (total
== sizeof(buf
))
45 fprintf(stderr
, "buffer too small to read input!\n");
52 * Write output data from chunk to stream
54 static bool write_to_stream(FILE *stream
, chunk_t data
)
56 size_t len
, total
= 0;
58 while (total
< data
.len
)
60 len
= fwrite(data
.ptr
+ total
, 1, data
.len
- total
, stream
);
71 * Verify PKCS#7 signed-data
73 static int verify(chunk_t chunk
)
75 container_t
*container
;
77 enumerator_t
*enumerator
;
82 bool verified
= FALSE
;
84 container
= lib
->creds
->create(lib
->creds
, CRED_CONTAINER
, CONTAINER_PKCS7
,
85 BUILD_BLOB_ASN1_DER
, chunk
, BUILD_END
);
91 if (container
->get_type(container
) != CONTAINER_PKCS7_SIGNED_DATA
)
93 fprintf(stderr
, "verification failed, container is %N\n",
94 container_type_names
, container
->get_type(container
));
95 container
->destroy(container
);
99 pkcs7
= (pkcs7_t
*)container
;
100 enumerator
= container
->create_signature_enumerator(container
);
101 while (enumerator
->enumerate(enumerator
, &auth
))
104 cert
= auth
->get(auth
, AUTH_RULE_SUBJECT_CERT
);
107 fprintf(stderr
, "signed by '%Y'", cert
->get_subject(cert
));
109 if (pkcs7
->get_attribute(pkcs7
, OID_PKCS9_SIGNING_TIME
,
112 t
= asn1_to_time(&data
, ASN1_UTCTIME
);
113 if (t
!= UNDEFINED_TIME
)
115 fprintf(stderr
, " at %T", &t
, FALSE
);
119 fprintf(stderr
, "\n");
122 enumerator
->destroy(enumerator
);
126 fprintf(stderr
, "no trusted signature found\n");
131 if (container
->get_data(container
, &data
))
133 write_to_stream(stdout
, data
);
141 container
->destroy(container
);
143 return verified ?
0 : 1;
147 * Sign data into PKCS#7 signed-data
149 static int sign(chunk_t chunk
, certificate_t
*cert
, private_key_t
*key
)
151 container_t
*container
;
155 container
= lib
->creds
->create(lib
->creds
,
156 CRED_CONTAINER
, CONTAINER_PKCS7_SIGNED_DATA
,
158 BUILD_SIGNING_CERT
, cert
,
159 BUILD_SIGNING_KEY
, key
,
163 if (container
->get_encoding(container
, &encoding
))
165 write_to_stream(stdout
, encoding
);
168 container
->destroy(container
);
174 * Encrypt data to a PKCS#7 enveloped-data
176 static int encrypt(chunk_t chunk
, certificate_t
*cert
)
178 container_t
*container
;
182 container
= lib
->creds
->create(lib
->creds
,
183 CRED_CONTAINER
, CONTAINER_PKCS7_ENVELOPED_DATA
,
184 BUILD_BLOB
, chunk
, BUILD_CERT
, cert
,
188 if (container
->get_encoding(container
, &encoding
))
190 write_to_stream(stdout
, encoding
);
193 container
->destroy(container
);
199 * Decrypt PKCS#7 enveloped-data
201 static int decrypt(chunk_t chunk
)
203 container_t
*container
;
206 container
= lib
->creds
->create(lib
->creds
, CRED_CONTAINER
, CONTAINER_PKCS7
,
207 BUILD_BLOB_ASN1_DER
, chunk
, BUILD_END
);
212 if (container
->get_type(container
) != CONTAINER_PKCS7_ENVELOPED_DATA
)
214 fprintf(stderr
, "decryption failed, container is %N\n",
215 container_type_names
, container
->get_type(container
));
216 container
->destroy(container
);
219 if (!container
->get_data(container
, &data
))
221 fprintf(stderr
, "PKCS#7 decryption failed\n");
222 container
->destroy(container
);
225 container
->destroy(container
);
227 write_to_stream(stdout
, data
);
234 * Show info about PKCS#7 container
236 static int show(chunk_t chunk
)
238 container_t
*container
;
240 enumerator_t
*enumerator
;
244 container
= lib
->creds
->create(lib
->creds
, CRED_CONTAINER
, CONTAINER_PKCS7
,
245 BUILD_BLOB_ASN1_DER
, chunk
, BUILD_END
);
250 fprintf(stderr
, "%N\n", container_type_names
, container
->get_type(container
));
252 if (container
->get_type(container
) == CONTAINER_PKCS7_SIGNED_DATA
)
254 pkcs7
= (pkcs7_t
*)container
;
255 enumerator
= pkcs7
->create_cert_enumerator(pkcs7
);
256 while (enumerator
->enumerate(enumerator
, &cert
))
258 if (cert
->get_encoding(cert
, CERT_PEM
, &data
))
260 printf("%.*s", (int)data
.len
, data
.ptr
);
264 enumerator
->destroy(enumerator
);
266 container
->destroy(container
);
271 * Wrap/Unwrap PKCs#7 containers
275 char *arg
, *file
= NULL
;
276 private_key_t
*key
= NULL
;
277 certificate_t
*cert
= NULL
;
278 chunk_t data
= chunk_empty
;
291 creds
= mem_cred_create();
295 switch (command_getopt(&arg
))
298 creds
->destroy(creds
);
299 return command_usage(NULL
);
339 key
= lib
->creds
->create(lib
->creds
,
340 CRED_PRIVATE_KEY
, KEY_RSA
,
341 BUILD_FROM_FILE
, arg
, BUILD_END
);
344 fprintf(stderr
, "parsing private key failed\n");
347 creds
->add_key(creds
, key
);
350 cert
= lib
->creds
->create(lib
->creds
,
351 CRED_CERTIFICATE
, CERT_X509
,
352 BUILD_FROM_FILE
, arg
, BUILD_END
);
355 fprintf(stderr
, "parsing certificate failed\n");
358 creds
->add_cert(creds
, TRUE
, cert
);
364 creds
->destroy(creds
);
365 return command_usage("invalid --pkcs7 option");
372 in
= fopen(file
, "r");
375 data
= read_from_stream(in
);
381 data
= read_from_stream(stdin
);
386 fprintf(stderr
, "reading input failed!\n");
389 if (op
!= OP_SHOW
&& !cert
)
391 fprintf(stderr
, "requiring a certificate!\n");
395 lib
->credmgr
->add_local_set(lib
->credmgr
, &creds
->set
, FALSE
);
402 fprintf(stderr
, "signing requires a private key\n");
406 res
= sign(data
, cert
, key
);
412 res
= encrypt(data
, cert
);
417 fprintf(stderr
, "decryption requires a private key\n");
430 lib
->credmgr
->remove_local_set(lib
->credmgr
, &creds
->set
);
433 creds
->destroy(creds
);
439 * Register the command.
441 static void __attribute__ ((constructor
))reg()
443 command_register((command_t
) {
444 pkcs7
, '7', "pkcs7", "PKCS#7 wrap/unwrap functions",
445 {"--sign | --verify | --encrypt | --decrypt",
446 "--certificate+ [--key]"},
448 {"help", 'h', 0, "show usage information"},
449 {"sign", 's', 0, "create PKCS#7 signed-data"},
450 {"verify", 'u', 0, "verify PKCS#7 signed-data"},
451 {"encrypt", 'e', 0, "create PKCS#7 enveloped-data"},
452 {"decrypt", 'd', 0, "decrypt PKCS#7 enveloped-data"},
453 {"show", 'p', 0, "show info about PKCS#7, print certificates"},
454 {"in", 'i', 1, "input file, default: stdin"},
455 {"key", 'k', 1, "path to private key for sign/decryp"},
456 {"cert", 'c', 1, "path to certificate for sign/verify/encryp"},