• 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 <gmssl/mem.h>
16 #include <gmssl/rand.h>
17 #include <gmssl/x509.h>
18 #include <gmssl/x509_ext.h>
19 #include <gmssl/x509_req.h>
20 
21 
22 static const char *options = "[-in pem] -days num -cacert pem -key pem [-pass str] [-out pem] "
23 	"-key_usage oid -path_len_constraint num  -crl_url url\n";
24 
ext_key_usage_set(int * usages,const char * usage_name)25 static int ext_key_usage_set(int *usages, const char *usage_name)
26 {
27 	int flag = 0;
28 	if (x509_key_usage_from_name(&flag, usage_name) != 1) {
29 		return -1;
30 	}
31 	*usages |= flag;
32 	return 1;
33 }
34 
reqsign_main(int argc,char ** argv)35 int reqsign_main(int argc, char **argv)
36 {
37 	int ret = 1;
38 	char *prog = argv[0];
39 	char *infile = NULL;
40 	int days = 0;
41 	char *cacertfile = NULL;
42 	char *keyfile = NULL;
43 	char *pass = NULL;
44 	char *outfile = NULL;
45 	FILE *infp = stdin;
46 	FILE *cacertfp = NULL;
47 	FILE *keyfp = NULL;
48 	FILE *outfp = stdout;
49 
50 	uint8_t req[512];
51 	size_t reqlen;
52 	const uint8_t *subject;
53 	size_t subject_len;
54 	SM2_KEY subject_public_key;
55 
56 	uint8_t cacert[1024];
57 	size_t cacertlen;
58 	const uint8_t *issuer;
59 	size_t issuer_len;
60 	SM2_KEY issuer_public_key;
61 
62 	SM2_KEY sm2_key;
63 
64 	uint8_t cert[1024];
65 	size_t certlen;
66 	uint8_t serial[12];
67 	time_t not_before, not_after;
68 	uint8_t exts[512];
69 	size_t extslen = 0;
70 	int key_usage = 0;
71 	int path_len_constraint = -1;
72 
73 	argc--;
74 	argv++;
75 
76 	if (argc < 1) {
77 		fprintf(stderr, "usage: %s %s\n", prog, options);
78 		return 1;
79 	}
80 
81 	while (argc >= 1) {
82 		if (!strcmp(*argv, "-help")) {
83 			printf("usage: %s %s\n", prog, options);
84 			ret = 0;
85 			goto end;
86 		} else if (!strcmp(*argv, "-in")) {
87 			if (--argc < 1) goto bad;
88 			infile = *(++argv);
89 			if (!(infp = fopen(infile, "r"))) {
90 				fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno));
91 				goto end;
92 			}
93 		} else if (!strcmp(*argv, "-days")) {
94 			if (--argc < 1) goto bad;
95 			days = atoi(*(++argv));
96 			if (days <= 0) {
97 				fprintf(stderr, "%s: invalid '-days' value\n", prog);
98 				goto end;
99 			}
100 		} else if (!strcmp(*argv, "-key_usage")) {
101 			if (--argc < 1) goto bad;
102 			if (ext_key_usage_set(&key_usage, *(++argv)) != 1) {
103 				fprintf(stderr, "%s: set KeyUsage extenstion failure\n", prog);
104 				goto end;
105 			}
106 		} else if (!strcmp(*argv, "-path_len_constraint")) {
107 			if (--argc < 1) goto bad;
108 			path_len_constraint = atoi(*(++argv));
109 			if (path_len_constraint < 0) {
110 				fprintf(stderr, "%s: invalid value for '-path_len_constraint'\n", prog);
111 				goto end;
112 			}
113 		} else if (!strcmp(*argv, "-crl_url")) {
114 			if (--argc < 1) goto bad;
115 			//crl_url = *(++argv);
116 		} else if (!strcmp(*argv, "-cacert")) {
117 			if (--argc < 1) goto bad;
118 			cacertfile = *(++argv);
119 			if (!(cacertfp = fopen(cacertfile, "r"))) {
120 				fprintf(stderr, "%s: invalid -key_usage value\n", prog);
121 				goto end;
122 			}
123 		} else if (!strcmp(*argv, "-key")) {
124 			if (--argc < 1) goto bad;
125 			keyfile = *(++argv);
126 			if (!(keyfp = fopen(keyfile, "r"))) {
127 				fprintf(stderr, "%s: open '%s' failure : %s\n", prog, keyfile, strerror(errno));
128 				goto end;
129 			}
130 		} else if (!strcmp(*argv, "-pass")) {
131 			if (--argc < 1) goto bad;
132 			pass = *(++argv);
133 		} else if (!strcmp(*argv, "-out")) {
134 			if (--argc < 1) goto bad;
135 			outfile = *(++argv);
136 			if (!(outfp = fopen(outfile, "w"))) {
137 				fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno));
138 				goto end;
139 			}
140 		} else {
141 			fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv);
142 			goto end;
143 bad:
144 			fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv);
145 			goto end;
146 		}
147 
148 		argc--;
149 		argv++;
150 	}
151 
152 	if (!days) {
153 		fprintf(stderr, "%s: '-days' option required\n", prog);
154 		goto end;
155 	}
156 	if (!cacertfile) {
157 		fprintf(stderr, "%s: '-cacert' option required\n", prog);
158 		goto end;
159 	}
160 	if (!keyfile) {
161 		fprintf(stderr, "%s: '-key' option required\n", prog);
162 		goto end;
163 	}
164 	if (!pass) {
165 		fprintf(stderr, "%s: '-pass' option required\n", prog);
166 		goto end;
167 	}
168 
169 
170 	if (x509_req_from_pem(req, &reqlen, sizeof(req), infp) != 1
171 		|| x509_req_get_details(req, reqlen,
172 			NULL, &subject, &subject_len, &subject_public_key,
173 			NULL, NULL, NULL, NULL, NULL) != 1) {
174 		fprintf(stderr, "%s: parse CSR failure\n", prog);
175 		goto end;
176 	}
177 
178 	if (x509_cert_from_pem(cacert, &cacertlen, sizeof(cacert), cacertfp) != 1
179 		|| x509_cert_get_subject(cacert, cacertlen, &issuer, &issuer_len) != 1
180 		|| x509_cert_get_subject_public_key(cacert, cacertlen, &issuer_public_key) != 1) {
181 		fprintf(stderr, "%s: parse CA certificate failure\n", prog);
182 		goto end;
183 	}
184 
185 	if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1) {
186 		fprintf(stderr, "%s: load private key failure\n", prog);
187 		goto end;
188 	}
189 	if (sm2_public_key_equ(&sm2_key, &issuer_public_key) != 1) {
190 		fprintf(stderr, "%s: private key and CA certificate not match\n", prog);
191 		goto end;
192 	}
193 
194 	if (rand_bytes(serial, sizeof(serial)) != 1) {
195 		fprintf(stderr, "%s: inner error\n", prog);
196 		goto end;
197 	}
198 	time(&not_before);
199 
200 
201 	if (x509_exts_add_key_usage(exts, &extslen, sizeof(exts), 1, key_usage) != 1) {
202 		fprintf(stderr, "%s: inner error\n", prog);
203 		goto end;
204 	}
205 	if (path_len_constraint >= 0) {
206 		if (x509_exts_add_basic_constraints(exts, &extslen, sizeof(exts), 1, 1, path_len_constraint) != 1) {
207 			fprintf(stderr, "%s: inner error\n", prog);
208 			goto end;
209 		}
210 	}
211 	if (x509_exts_add_default_authority_key_identifier(exts, &extslen, sizeof(exts), &sm2_key) != 1) {
212 		fprintf(stderr, "%s: inner error\n", prog);
213 		goto end;
214 	}
215 
216 	if (x509_validity_add_days(&not_after, not_before, days) != 1
217 		|| x509_cert_sign(
218 			cert, &certlen, sizeof(cert),
219 			X509_version_v3,
220 			serial, sizeof(serial),
221 			OID_sm2sign_with_sm3,
222 			issuer, issuer_len,
223 			not_before, not_after,
224 			subject, subject_len,
225 			&subject_public_key,
226 			NULL, 0,
227 			NULL, 0,
228 			exts, extslen,
229 			&sm2_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1) {
230 		fprintf(stderr, "%s: inner error\n", prog);
231 		goto end;
232 	}
233 	if (x509_cert_to_pem(cert, certlen, outfp) != 1) {
234 		fprintf(stderr, "%s: output certificate failed\n", prog);
235 		goto end;
236 	}
237 	ret = 0;
238 end:
239 	gmssl_secure_clear(&sm2_key, sizeof(SM2_KEY));
240 	if (keyfp) fclose(keyfp);
241 	if (cacertfp) fclose(cacertfp);
242 	if (infile && infp) fclose(infp);
243 	if (outfile && outfp) fclose(outfp);
244 	return ret;
245 }
246