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
);
34 if (len
< (sizeof(buf
) - total
))
42 return chunk_clone(chunk_create(buf
, total
+ len
));
46 if (total
== sizeof(buf
))
48 fprintf(stderr
, "buffer too small to read input!\n");
55 * Write output data from chunk to stream
57 static bool write_to_stream(FILE *stream
, chunk_t data
)
59 size_t len
, total
= 0;
61 while (total
< data
.len
)
63 len
= fwrite(data
.ptr
+ total
, 1, data
.len
- total
, stream
);
74 * Verify PKCS#7 signed-data
76 static int verify(chunk_t chunk
)
78 container_t
*container
;
80 enumerator_t
*enumerator
;
85 bool verified
= FALSE
;
87 container
= lib
->creds
->create(lib
->creds
, CRED_CONTAINER
, CONTAINER_PKCS7
,
88 BUILD_BLOB_ASN1_DER
, chunk
, BUILD_END
);
94 if (container
->get_type(container
) != CONTAINER_PKCS7_SIGNED_DATA
)
96 fprintf(stderr
, "verification failed, container is %N\n",
97 container_type_names
, container
->get_type(container
));
98 container
->destroy(container
);
102 pkcs7
= (pkcs7_t
*)container
;
103 enumerator
= container
->create_signature_enumerator(container
);
104 while (enumerator
->enumerate(enumerator
, &auth
))
107 cert
= auth
->get(auth
, AUTH_RULE_SUBJECT_CERT
);
110 fprintf(stderr
, "signed by '%Y'", cert
->get_subject(cert
));
112 if (pkcs7
->get_attribute(pkcs7
, OID_PKCS9_SIGNING_TIME
,
115 t
= asn1_to_time(&data
, ASN1_UTCTIME
);
116 if (t
!= UNDEFINED_TIME
)
118 fprintf(stderr
, " at %T", &t
, FALSE
);
122 fprintf(stderr
, "\n");
125 enumerator
->destroy(enumerator
);
129 fprintf(stderr
, "no trusted signature found\n");
134 if (container
->get_data(container
, &data
))
136 write_to_stream(stdout
, data
);
144 container
->destroy(container
);
146 return verified ?
0 : 1;
150 * Sign data into PKCS#7 signed-data
152 static int sign(chunk_t chunk
, certificate_t
*cert
, private_key_t
*key
)
154 container_t
*container
;
158 container
= lib
->creds
->create(lib
->creds
,
159 CRED_CONTAINER
, CONTAINER_PKCS7_SIGNED_DATA
,
161 BUILD_SIGNING_CERT
, cert
,
162 BUILD_SIGNING_KEY
, key
,
166 if (container
->get_encoding(container
, &encoding
))
168 write_to_stream(stdout
, encoding
);
171 container
->destroy(container
);
177 * Encrypt data to a PKCS#7 enveloped-data
179 static int encrypt(chunk_t chunk
, certificate_t
*cert
)
181 container_t
*container
;
185 container
= lib
->creds
->create(lib
->creds
,
186 CRED_CONTAINER
, CONTAINER_PKCS7_ENVELOPED_DATA
,
187 BUILD_BLOB
, chunk
, BUILD_CERT
, cert
,
191 if (container
->get_encoding(container
, &encoding
))
193 write_to_stream(stdout
, encoding
);
196 container
->destroy(container
);
202 * Decrypt PKCS#7 enveloped-data
204 static int decrypt(chunk_t chunk
)
206 container_t
*container
;
209 container
= lib
->creds
->create(lib
->creds
, CRED_CONTAINER
, CONTAINER_PKCS7
,
210 BUILD_BLOB_ASN1_DER
, chunk
, BUILD_END
);
215 if (container
->get_type(container
) != CONTAINER_PKCS7_ENVELOPED_DATA
)
217 fprintf(stderr
, "decryption failed, container is %N\n",
218 container_type_names
, container
->get_type(container
));
219 container
->destroy(container
);
222 if (!container
->get_data(container
, &data
))
224 fprintf(stderr
, "PKCS#7 decryption failed\n");
225 container
->destroy(container
);
228 container
->destroy(container
);
230 write_to_stream(stdout
, data
);
237 * Show info about PKCS#7 container
239 static int show(chunk_t chunk
)
241 container_t
*container
;
243 enumerator_t
*enumerator
;
247 container
= lib
->creds
->create(lib
->creds
, CRED_CONTAINER
, CONTAINER_PKCS7
,
248 BUILD_BLOB_ASN1_DER
, chunk
, BUILD_END
);
253 fprintf(stderr
, "%N\n", container_type_names
, container
->get_type(container
));
255 if (container
->get_type(container
) == CONTAINER_PKCS7_SIGNED_DATA
)
257 pkcs7
= (pkcs7_t
*)container
;
258 enumerator
= pkcs7
->create_cert_enumerator(pkcs7
);
259 while (enumerator
->enumerate(enumerator
, &cert
))
261 if (cert
->get_encoding(cert
, CERT_PEM
, &data
))
263 printf("%.*s", (int)data
.len
, data
.ptr
);
267 enumerator
->destroy(enumerator
);
269 container
->destroy(container
);
274 * Wrap/Unwrap PKCs#7 containers
278 char *arg
, *file
= NULL
;
279 private_key_t
*key
= NULL
;
280 certificate_t
*cert
= NULL
;
281 chunk_t data
= chunk_empty
;
294 creds
= mem_cred_create();
298 switch (command_getopt(&arg
))
301 creds
->destroy(creds
);
302 return command_usage(NULL
);
342 key
= lib
->creds
->create(lib
->creds
,
343 CRED_PRIVATE_KEY
, KEY_RSA
,
344 BUILD_FROM_FILE
, arg
, BUILD_END
);
347 fprintf(stderr
, "parsing private key failed\n");
350 creds
->add_key(creds
, key
);
353 cert
= lib
->creds
->create(lib
->creds
,
354 CRED_CERTIFICATE
, CERT_X509
,
355 BUILD_FROM_FILE
, arg
, BUILD_END
);
358 fprintf(stderr
, "parsing certificate failed\n");
361 creds
->add_cert(creds
, TRUE
, cert
);
367 creds
->destroy(creds
);
368 return command_usage("invalid --pkcs7 option");
375 in
= fopen(file
, "r");
378 data
= read_from_stream(in
);
384 data
= read_from_stream(stdin
);
389 fprintf(stderr
, "reading input failed!\n");
392 if (op
!= OP_SHOW
&& !cert
)
394 fprintf(stderr
, "requiring a certificate!\n");
398 lib
->credmgr
->add_local_set(lib
->credmgr
, &creds
->set
, FALSE
);
405 fprintf(stderr
, "signing requires a private key\n");
409 res
= sign(data
, cert
, key
);
415 res
= encrypt(data
, cert
);
420 fprintf(stderr
, "decryption requires a private key\n");
433 lib
->credmgr
->remove_local_set(lib
->credmgr
, &creds
->set
);
436 creds
->destroy(creds
);
442 * Register the command.
444 static void __attribute__ ((constructor
))reg()
446 command_register((command_t
) {
447 pkcs7
, '7', "pkcs7", "PKCS#7 wrap/unwrap functions",
448 {"--sign | --verify | --encrypt | --decrypt",
449 "--certificate+ [--key]"},
451 {"help", 'h', 0, "show usage information"},
452 {"sign", 's', 0, "create PKCS#7 signed-data"},
453 {"verify", 'u', 0, "verify PKCS#7 signed-data"},
454 {"encrypt", 'e', 0, "create PKCS#7 enveloped-data"},
455 {"decrypt", 'd', 0, "decrypt PKCS#7 enveloped-data"},
456 {"show", 'p', 0, "show info about PKCS#7, print certificates"},
457 {"in", 'i', 1, "input file, default: stdin"},
458 {"key", 'k', 1, "path to private key for sign/decryp"},
459 {"cert", 'c', 1, "path to certificate for sign/verify/encryp"},