61e829fdff8abbc5adddf95701f9394370bd0aca
2 * Copyright (C) 2013 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
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>.
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
20 #include "sshkey_builder.h"
23 #include <asn1/asn1.h>
24 #include <bio/bio_reader.h>
25 #include <utils/debug.h>
27 #define ECDSA_PREFIX "ecdsa-sha2-"
30 * Parse an EC domain parameter identifier as defined in RFC 5656
32 static chunk_t
parse_ec_identifier(chunk_t identifier
)
34 chunk_t oid
= chunk_empty
;
36 if (chunk_equals(identifier
, chunk_from_str("nistp256")))
38 oid
= asn1_build_known_oid(OID_PRIME256V1
);
40 else if (chunk_equals(identifier
, chunk_from_str("nistp384")))
42 oid
= asn1_build_known_oid(OID_SECT384R1
);
44 else if (chunk_equals(identifier
, chunk_from_str("nistp521")))
46 oid
= asn1_build_known_oid(OID_SECT521R1
);
52 if (snprintf(ascii
, sizeof(ascii
), "%.*s", (int)identifier
.len
,
53 identifier
.ptr
) < sizeof(ascii
))
55 oid
= asn1_wrap(ASN1_OID
, "m", asn1_oid_from_string(ascii
));
62 * Load a generic public key from an SSH key blob
64 static sshkey_public_key_t
*parse_public_key(chunk_t blob
)
69 reader
= bio_reader_create(blob
);
70 if (!reader
->read_data32(reader
, &format
))
72 DBG1(DBG_LIB
, "invalid key format in SSH key");
73 reader
->destroy(reader
);
76 if (chunk_equals(format
, chunk_from_str("ssh-rsa")))
80 if (!reader
->read_data32(reader
, &e
) ||
81 !reader
->read_data32(reader
, &n
))
83 DBG1(DBG_LIB
, "invalid RSA key in SSH key");
84 reader
->destroy(reader
);
87 reader
->destroy(reader
);
88 return lib
->creds
->create(lib
->creds
, CRED_PUBLIC_KEY
, KEY_RSA
,
89 BUILD_RSA_MODULUS
, n
, BUILD_RSA_PUB_EXP
, e
, BUILD_END
);
91 else if (format
.len
> strlen(ECDSA_PREFIX
) &&
92 strpfx(format
.ptr
, ECDSA_PREFIX
))
94 chunk_t ec_blob
, identifier
, q
, oid
, encoded
;
95 sshkey_public_key_t
*key
;
97 ec_blob
= reader
->peek(reader
);
98 reader
->destroy(reader
);
99 reader
= bio_reader_create(ec_blob
);
100 if (!reader
->read_data32(reader
, &identifier
) ||
101 !reader
->read_data32(reader
, &q
))
103 DBG1(DBG_LIB
, "invalid ECDSA key in SSH key");
104 reader
->destroy(reader
);
107 oid
= parse_ec_identifier(identifier
);
110 DBG1(DBG_LIB
, "invalid ECDSA key identifier in SSH key");
111 reader
->destroy(reader
);
114 reader
->destroy(reader
);
115 /* build key from subjectPublicKeyInfo */
116 encoded
= asn1_wrap(ASN1_SEQUENCE
, "mm",
117 asn1_wrap(ASN1_SEQUENCE
, "mm",
118 asn1_build_known_oid(OID_EC_PUBLICKEY
), oid
),
119 asn1_bitstring("c", q
));
120 key
= lib
->creds
->create(lib
->creds
, CRED_PUBLIC_KEY
,
121 KEY_ECDSA
, BUILD_BLOB_ASN1_DER
, encoded
, BUILD_END
);
122 chunk_free(&encoded
);
125 DBG1(DBG_LIB
, "unsupported SSH key format %.*s", (int)format
.len
,
127 reader
->destroy(reader
);
132 * Load SSH key from a FILE stream, closes the stream
134 static sshkey_public_key_t
*load_from_stream(FILE *file
)
136 sshkey_public_key_t
*public = NULL
;
137 chunk_t blob
= chunk_empty
;
138 enumerator_t
*enumerator
;
139 char line
[1024], *token
;
141 while (!public && fgets(line
, sizeof(line
), file
))
142 { /* the format is: ssh-[rsa|ecdsa-...] <key(base64)> <identifier> */
143 if (!strpfx(line
, "ssh-"))
147 enumerator
= enumerator_create_token(line
, " ", " ");
148 if (enumerator
->enumerate(enumerator
, &token
) &&
149 enumerator
->enumerate(enumerator
, &token
))
151 blob
= chunk_from_base64(chunk_from_str(token
), NULL
);
153 enumerator
->destroy(enumerator
);
156 public = parse_public_key(blob
);
165 * Load SSH key from FD
167 static sshkey_public_key_t
*load_from_fd(int fd
)
171 /* dup the FD as it gets closed in fclose() */
177 stream
= fdopen(fd
, "r");
183 return load_from_stream(stream
);
187 * Load SSH key from file
189 static sshkey_public_key_t
*load_from_file(char *file
)
193 stream
= fopen(file
, "r");
196 DBG1(DBG_LIB
, " opening '%s' failed: %s", file
, strerror(errno
));
199 return load_from_stream(stream
);
205 sshkey_public_key_t
*sshkey_public_key_load(key_type_t type
, va_list args
)
207 chunk_t blob
= chunk_empty
;
213 switch (va_arg(args
, builder_part_t
))
215 case BUILD_BLOB_SSHKEY
:
216 blob
= va_arg(args
, chunk_t
);
218 case BUILD_FROM_FILE
:
219 file
= va_arg(args
, char*);
222 fd
= va_arg(args
, int);
233 return parse_public_key(blob
);
237 return load_from_file(file
);
241 return load_from_fd(fd
);