• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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