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 #include <gmssl/error.h>
19
20
21 /*
22 302 typedef struct {
23 303 uint8_t *certs;
24 304 size_t certs_len;
25 305 SM2_KEY *sign_key;
26 306 } CMS_CERTS_AND_KEY;
27
28
29
30 输出长度主要由输入长度和
31
32 */
33
34 static const char *options = "-key file -pass str -cert file -in file [-out file]";
35
cmssign_main(int argc,char ** argv)36 int cmssign_main(int argc, char **argv)
37 {
38 int ret = 1;
39 char *prog = argv[0];
40 char *keyfile = NULL;
41 char *pass = NULL;
42 char *certfile = NULL;
43 char *infile = NULL;
44 char *outfile = NULL;
45 FILE *keyfp = NULL;
46 FILE *certfp = NULL;
47 FILE *infp = NULL;
48 FILE *outfp = stdout;
49 SM2_KEY key;
50 uint8_t cert[1024];
51 size_t certlen;
52 struct stat st;
53 uint8_t *in = NULL;
54 size_t inlen;
55 uint8_t *cms = NULL;
56 size_t cmslen, cms_maxlen;
57 CMS_CERTS_AND_KEY cert_and_key;
58
59 int content_type;
60 uint8_t *content = NULL;
61 size_t content_len;
62
63 const uint8_t *rcpt_infos;
64 size_t rcpt_infos_len;
65 const uint8_t *shared_info1;
66 const uint8_t *shared_info2;
67 size_t shared_info1_len, shared_info2_len;
68
69 argc--;
70 argv++;
71
72 if (argc < 1) {
73 fprintf(stderr, "usage: %s %s\n", prog, options);
74 return 1;
75 }
76
77 while (argc > 1) {
78 if (!strcmp(*argv, "-help")) {
79 printf("usage: %s %s\n", prog, options);
80 ret = 0;
81 goto end;
82 } else if (!strcmp(*argv, "-key")) {
83 if (--argc < 1) goto bad;
84 keyfile = *(++argv);
85 if (!(keyfp = fopen(keyfile, "r"))) {
86 fprintf(stderr, "%s: open '%s' failure : %s\n", prog, keyfile, strerror(errno));
87 goto end;
88 }
89 } else if (!strcmp(*argv, "-pass")) {
90 if (--argc < 1) goto bad;
91 pass = *(++argv);
92 } else if (!strcmp(*argv, "-cert")) {
93 if (--argc < 1) goto bad;
94 certfile = *(++argv);
95 if (!(certfp = fopen(certfile, "r"))) {
96 fprintf(stderr, "%s: open '%s' failure : %s\n", prog, certfile, strerror(errno));
97 goto end;
98 }
99 } else if (!strcmp(*argv, "-in")) {
100 if (--argc < 1) goto bad;
101 infile = *(++argv);
102 if (!(infp = fopen(infile, "r"))) {
103 fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno));
104 goto end;
105 }
106 } else if (!strcmp(*argv, "-out")) {
107 if (--argc < 1) goto bad;
108 outfile = *(++argv);
109 if (!(outfp = fopen(outfile, "w"))) {
110 fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno));
111 goto end;
112 }
113 } else {
114 fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv);
115 goto end;
116 bad:
117 fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv);
118 goto end;
119 }
120
121 argc--;
122 argv++;
123 }
124
125 if (!keyfile) {
126 fprintf(stderr, "%s: '-key' option required\n", prog);
127 goto end;
128 }
129 if (!pass) {
130 fprintf(stderr, "%s: '-pass' option required\n", prog);
131 goto end;
132 }
133 if (!certfile) {
134 fprintf(stderr, "%s: '-cert' option required\n", prog);
135 goto end;
136 }
137 if (!infile) {
138 fprintf(stderr, "%s: '-in' option required\n", prog);
139 goto end;
140 }
141
142 if (sm2_private_key_info_decrypt_from_pem(&key, pass, keyfp) != 1) {
143 fprintf(stderr, "%s: private key decryption failure\n", prog);
144 goto end;
145 }
146 if (x509_cert_from_pem(cert, &certlen, sizeof(cert), certfp) != 1) {
147 fprintf(stderr, "%s: load certificate failure\n", prog);
148 goto end;
149 }
150 {
151 SM2_KEY public_key;
152 if (x509_cert_get_subject_public_key(cert, certlen, &public_key) != 1) {
153 fprintf(stderr, "%s: parse certficate failure\n", prog);
154 goto end;
155 }
156 if (sm2_public_key_equ(&key, &public_key) != 1) {
157 fprintf(stderr, "%s: key and cert are not match!\n", prog);
158 goto end;
159 }
160 }
161
162 cert_and_key.certs = cert;
163 cert_and_key.certs_len = certlen;
164 cert_and_key.sign_key = &key;
165
166 if (fstat(fileno(infp), &st) < 0) {
167 fprintf(stderr, "%s: access file error : %s\n", prog, strerror(errno));
168 goto end;
169 }
170 if ((inlen = st.st_size) <= 0) {
171 fprintf(stderr, "%s: invalid input length\n", prog);
172 goto end;
173 }
174 if (!(in = malloc(inlen))) {
175 fprintf(stderr, "%s: malloc failure\n", prog);
176 goto end;
177 }
178 if (fread(in, 1, inlen, infp) != inlen) {
179 fprintf(stderr, "%s: read file error : %s\n", prog, strerror(errno));
180 goto end;
181 }
182
183 cms_maxlen = (inlen * 4)/3 + 4096; // 主要由SignerInfos,其中的DN长度决定
184 if (!(cms = malloc(cms_maxlen))) {
185 fprintf(stderr, "%s: malloc failure\n", prog);
186 goto end;
187 }
188
189 if (cms_sign(cms, &cmslen, &cert_and_key, 1, OID_cms_data, in, inlen, NULL, 0) != 1) {
190 fprintf(stderr, "%s: sign failure\n", prog);
191 goto end;
192 }
193
194 if (cms_to_pem(cms, cmslen, outfp) != 1) {
195 fprintf(stderr, "%s: output failure\n", prog);
196 goto end;
197 }
198
199 ret = 0;
200
201 end:
202 if (infile && infp) fclose(infp);
203 if (outfile && outfp) fclose(outfp);
204 if (keyfile && keyfp) fclose(keyfp);
205 if (cms) free(cms);
206 if (in) free(in);
207 return ret;
208 }
209