Annotation of embedaddon/strongswan/src/libstrongswan/plugins/sshkey/sshkey_builder.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2013-2018 Tobias Brunner
3: * HSR Hochschule fuer Technik Rapperswil
4: *
5: * This program is free software; you can redistribute it and/or modify it
6: * under the terms of the GNU General Public License as published by the
7: * Free Software Foundation; either version 2 of the License, or (at your
8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9: *
10: * This program is distributed in the hope that it will be useful, but
11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13: * for more details.
14: */
15:
16: #define _GNU_SOURCE /* for fmemopen() */
17: #include <unistd.h>
18: #include <stdio.h>
19: #include <errno.h>
20:
21: #include "sshkey_builder.h"
22:
23: #include <asn1/oid.h>
24: #include <asn1/asn1.h>
25: #include <bio/bio_reader.h>
26: #include <utils/debug.h>
27:
28: #define ECDSA_PREFIX "ecdsa-sha2-"
29:
30: /**
31: * Parse an EC domain parameter identifier as defined in RFC 5656
32: */
33: static chunk_t parse_ec_identifier(chunk_t identifier)
34: {
35: chunk_t oid = chunk_empty;
36:
37: if (chunk_equals(identifier, chunk_from_str("nistp256")))
38: {
39: oid = asn1_build_known_oid(OID_PRIME256V1);
40: }
41: else if (chunk_equals(identifier, chunk_from_str("nistp384")))
42: {
43: oid = asn1_build_known_oid(OID_SECT384R1);
44: }
45: else if (chunk_equals(identifier, chunk_from_str("nistp521")))
46: {
47: oid = asn1_build_known_oid(OID_SECT521R1);
48: }
49: else
50: {
51: char ascii[64];
52:
53: if (snprintf(ascii, sizeof(ascii), "%.*s", (int)identifier.len,
54: identifier.ptr) < sizeof(ascii))
55: {
56: oid = asn1_wrap(ASN1_OID, "m", asn1_oid_from_string(ascii));
57: }
58: }
59: return oid;
60: }
61:
62: /**
63: * Load a generic public key from an SSH key blob
64: */
65: static sshkey_public_key_t *parse_public_key(chunk_t blob)
66: {
67: bio_reader_t *reader;
68: chunk_t format;
69:
70: reader = bio_reader_create(blob);
71: if (!reader->read_data32(reader, &format))
72: {
73: DBG1(DBG_LIB, "invalid key format in SSH key");
74: reader->destroy(reader);
75: return NULL;
76: }
77: if (chunk_equals(format, chunk_from_str("ssh-rsa")))
78: {
79: chunk_t n, e;
80:
81: if (!reader->read_data32(reader, &e) ||
82: !reader->read_data32(reader, &n))
83: {
84: DBG1(DBG_LIB, "invalid RSA key in SSH key");
85: reader->destroy(reader);
86: return NULL;
87: }
88: reader->destroy(reader);
89: return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
90: BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END);
91: }
92: else if (chunk_equals(format, chunk_from_str("ssh-ed25519")))
93: {
94: chunk_t ed_key;
95:
96: if (!reader->read_data32(reader, &ed_key))
97: {
98: DBG1(DBG_LIB, "invalid Ed25519 key in SSH key");
99: reader->destroy(reader);
100: return NULL;
101: }
102: reader->destroy(reader);
103: return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED25519,
104: BUILD_EDDSA_PUB, ed_key, BUILD_END);
105: }
106: else if (chunk_equals(format, chunk_from_str("ssh-ed448")))
107: {
108: chunk_t ed_key;
109:
110: if (!reader->read_data32(reader, &ed_key))
111: {
112: DBG1(DBG_LIB, "invalid Ed448 key in SSH key");
113: reader->destroy(reader);
114: return NULL;
115: }
116: reader->destroy(reader);
117: return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448,
118: BUILD_EDDSA_PUB, ed_key, BUILD_END);
119: }
120: else if (format.len > strlen(ECDSA_PREFIX) &&
121: strpfx(format.ptr, ECDSA_PREFIX))
122: {
123: chunk_t ec_blob, identifier, q, oid, encoded;
124: sshkey_public_key_t *key;
125:
126: ec_blob = reader->peek(reader);
127: reader->destroy(reader);
128: reader = bio_reader_create(ec_blob);
129: if (!reader->read_data32(reader, &identifier) ||
130: !reader->read_data32(reader, &q))
131: {
132: DBG1(DBG_LIB, "invalid ECDSA key in SSH key");
133: reader->destroy(reader);
134: return NULL;
135: }
136: oid = parse_ec_identifier(identifier);
137: if (!oid.ptr)
138: {
139: DBG1(DBG_LIB, "invalid ECDSA key identifier in SSH key");
140: reader->destroy(reader);
141: return NULL;
142: }
143: reader->destroy(reader);
144: /* build key from subjectPublicKeyInfo */
145: encoded = asn1_wrap(ASN1_SEQUENCE, "mm",
146: asn1_wrap(ASN1_SEQUENCE, "mm",
147: asn1_build_known_oid(OID_EC_PUBLICKEY), oid),
148: asn1_bitstring("c", q));
149: key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY,
150: KEY_ECDSA, BUILD_BLOB_ASN1_DER, encoded, BUILD_END);
151: chunk_free(&encoded);
152: return key;
153: }
154: DBG1(DBG_LIB, "unsupported SSH key format %.*s", (int)format.len,
155: format.ptr);
156: reader->destroy(reader);
157: return NULL;
158: }
159:
160: /**
161: * Load SSH key from a FILE stream, closes the stream
162: */
163: static sshkey_public_key_t *load_from_stream(FILE *file)
164: {
165: sshkey_public_key_t *public = NULL;
166: chunk_t blob = chunk_empty;
167: enumerator_t *enumerator;
168: char line[1024], *token;
169:
170: while (!public && fgets(line, sizeof(line), file))
171: { /* the format is: ssh-<key-type> <key(base64)> <identifier> */
172: if (!strpfx(line, "ssh-rsa") && !strpfx(line, ECDSA_PREFIX) &&
173: !strpfx(line, "ssh-ed25519") && !strpfx(line, "ssh-ed448"))
174: {
175: continue;
176: }
177: enumerator = enumerator_create_token(line, " ", " ");
178: if (enumerator->enumerate(enumerator, &token) &&
179: enumerator->enumerate(enumerator, &token))
180: {
181: blob = chunk_from_base64(chunk_from_str(token), NULL);
182: }
183: enumerator->destroy(enumerator);
184: if (blob.ptr)
185: {
186: public = parse_public_key(blob);
187: chunk_free(&blob);
188: }
189: }
190: fclose(file);
191: return public;
192: }
193:
194: /**
195: * Load SSH key from a blob of data (most likely the content of a file)
196: */
197: static sshkey_public_key_t *load_from_blob(chunk_t blob)
198: {
199: FILE *stream;
200:
201: stream = fmemopen(blob.ptr, blob.len, "r");
202: if (!stream)
203: {
204: return NULL;
205: }
206: return load_from_stream(stream);
207: }
208:
209: /**
210: * Load SSH key from file
211: */
212: static sshkey_public_key_t *load_from_file(char *file)
213: {
214: FILE *stream;
215:
216: stream = fopen(file, "r");
217: if (!stream)
218: {
219: DBG1(DBG_LIB, " opening '%s' failed: %s", file, strerror(errno));
220: return NULL;
221: }
222: return load_from_stream(stream);
223: }
224:
225: /**
226: * See header.
227: */
228: sshkey_public_key_t *sshkey_public_key_load(key_type_t type, va_list args)
229: {
230: chunk_t sshkey = chunk_empty, blob = chunk_empty;
231: char *file = NULL;
232:
233: while (TRUE)
234: {
235: switch (va_arg(args, builder_part_t))
236: {
237: case BUILD_BLOB_SSHKEY:
238: sshkey = va_arg(args, chunk_t);
239: continue;
240: case BUILD_FROM_FILE:
241: file = va_arg(args, char*);
242: continue;
243: case BUILD_BLOB:
244: blob = va_arg(args, chunk_t);
245: continue;
246: case BUILD_END:
247: break;
248: default:
249: return NULL;
250: }
251: break;
252: }
253: if (sshkey.ptr)
254: {
255: return parse_public_key(sshkey);
256: }
257: if (file)
258: {
259: return load_from_file(file);
260: }
261: if (blob.ptr)
262: {
263: return load_from_blob(blob);
264: }
265: return NULL;
266: }
267:
268: /**
269: * See header.
270: */
271: certificate_t *sshkey_certificate_load(certificate_type_t type, va_list args)
272: {
273: certificate_t *cert;
274: public_key_t *key;
275: identification_t *subject = NULL;
276: char *file = NULL;
277:
278: while (TRUE)
279: {
280: switch (va_arg(args, builder_part_t))
281: {
282: case BUILD_FROM_FILE:
283: file = va_arg(args, char*);
284: continue;
285: case BUILD_SUBJECT:
286: subject = va_arg(args, identification_t*);
287: continue;
288: case BUILD_END:
289: break;
290: default:
291: return NULL;
292: }
293: break;
294: }
295: if (!file || !subject)
296: {
297: return NULL;
298: }
299: key = (public_key_t*)load_from_file(file);
300: if (!key)
301: {
302: return NULL;
303: }
304: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
305: CERT_TRUSTED_PUBKEY, BUILD_PUBLIC_KEY, key,
306: BUILD_SUBJECT, subject, BUILD_END);
307: key->destroy(key);
308: return cert;
309: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>