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(¬_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(¬_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