1 /*
2 * Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the License); you may
5 * not use this file except in compliance with the License.
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 */
9
10
11 #include <stdio.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <sys/stat.h>
16 #include <gmssl/x509.h>
17 #include <gmssl/cms.h>
18
19
20
21 static const char *options = "-key file -pass str -cert file -in file [-out file]";
22
cmsdecrypt_main(int argc,char ** argv)23 int cmsdecrypt_main(int argc, char **argv)
24 {
25 int ret = 1;
26 char *prog = argv[0];
27 char *keyfile = NULL;
28 char *pass = NULL;
29 char *certfile = NULL;
30 char *infile = NULL;
31 char *outfile = NULL;
32 FILE *keyfp = NULL;
33 FILE *certfp = NULL;
34 FILE *infp = NULL;
35 FILE *outfp = stdout;
36 uint8_t cert[1024];
37 size_t certlen;
38 struct stat st;
39 uint8_t *cms = NULL;
40 size_t cmslen, cms_maxlen;
41 SM2_KEY key;
42 int content_type;
43 uint8_t *content = NULL;
44 size_t content_len;
45 const uint8_t *rcpt_infos;
46 size_t rcpt_infos_len;
47 const uint8_t *shared_info1;
48 const uint8_t *shared_info2;
49 size_t shared_info1_len, shared_info2_len;
50
51 argc--;
52 argv++;
53
54 if (argc < 1) {
55 fprintf(stderr, "usage: %s %s\n", prog, options);
56 return 1;
57 }
58
59 while (argc > 1) {
60 if (!strcmp(*argv, "-help")) {
61 printf("usage: %s %s\n", prog, options);
62 ret = 0;
63 goto end;
64 } else if (!strcmp(*argv, "-key")) {
65 if (--argc < 1) goto bad;
66 keyfile = *(++argv);
67 if (!(keyfp = fopen(keyfile, "r"))) {
68 fprintf(stderr, "%s: open '%s' failure : %s\n", prog, keyfile, strerror(errno));
69 goto end;
70 }
71 } else if (!strcmp(*argv, "-pass")) {
72 if (--argc < 1) goto bad;
73 pass = *(++argv);
74 } else if (!strcmp(*argv, "-cert")) {
75 if (--argc < 1) goto bad;
76 certfile = *(++argv);
77 if (!(certfp = fopen(certfile, "r"))) {
78 fprintf(stderr, "%s: open '%s' failure : %s\n", prog, certfile, strerror(errno));
79 goto end;
80 }
81 } else if (!strcmp(*argv, "-in")) {
82 if (--argc < 1) goto bad;
83 infile = *(++argv);
84 if (!(infp = fopen(infile, "r"))) {
85 fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno));
86 goto end;
87 }
88 } else if (!strcmp(*argv, "-out")) {
89 if (--argc < 1) goto bad;
90 outfile = *(++argv);
91 if (!(outfp = fopen(outfile, "w"))) {
92 fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno));
93 goto end;
94 }
95 } else {
96 fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv);
97 goto end;
98 bad:
99 fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv);
100 goto end;
101 }
102
103 argc--;
104 argv++;
105 }
106
107 if (!keyfile) {
108 fprintf(stderr, "%s: '-key' option required\n", prog);
109 goto end;
110 }
111 if (!pass) {
112 fprintf(stderr, "%s: '-pass' option required\n", prog);
113 goto end;
114 }
115 if (!certfile) {
116 fprintf(stderr, "%s: '-cert' option required\n", prog);
117 goto end;
118 }
119 if (!infile) {
120 fprintf(stderr, "%s: '-in' option required\n", prog);
121 goto end;
122 }
123
124 if (sm2_private_key_info_decrypt_from_pem(&key, pass, keyfp) != 1) {
125 fprintf(stderr, "%s: private key decryption failure\n", prog);
126 goto end;
127 }
128 if (x509_cert_from_pem(cert, &certlen, sizeof(cert), certfp) != 1) {
129 fprintf(stderr, "%s: load certificate failure\n", prog);
130 goto end;
131 }
132
133 fstat(fileno(infp), &st);
134 cms_maxlen = (st.st_size * 3)/4 + 1;
135 if (!(cms = malloc(cms_maxlen))) {
136 fprintf(stderr, "%s: malloc failure\n", prog);
137 goto end;
138 }
139 if (cms_from_pem(cms, &cmslen, cms_maxlen, infp) != 1) {
140 fprintf(stderr, "%s: read CMS failure\n", prog);
141 goto end;
142 }
143
144 if (!(content = malloc(cmslen))) {
145 fprintf(stderr, "%s: malloc failure\n", prog);
146 goto end;
147 }
148
149 if (cms_deenvelop(cms, cmslen,
150 &key, cert, certlen,
151 &content_type, content, &content_len,
152 &rcpt_infos, &rcpt_infos_len,
153 &shared_info1, &shared_info1_len,
154 &shared_info2, &shared_info2_len) != 1) {
155 fprintf(stderr, "%s: decryption failure\n", prog);
156 goto end;
157 }
158 if (content_type != OID_cms_data) {
159 fprintf(stderr, "%s: invalid CMS content type: %s\n", prog, cms_content_type_name(content_type));
160 goto end;
161 }
162
163 if (fwrite(content, 1, content_len, outfp) != content_len) {
164 fprintf(stderr, "%s: output failure : %s\n", prog, strerror(errno));
165 goto end;
166 }
167
168 ret = 0;
169
170 end:
171 if (infile && infp) fclose(infp);
172 if (outfile && outfp) fclose(outfp);
173 if (keyfile && keyfp) fclose(keyfp);
174 if (cms) free(cms);
175 if (content) free(content);
176 return ret;
177 }
178