From a3232fa802b08447d3fb9534da5342992eee5337 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 14 Aug 2013 18:22:13 +0200 Subject: [PATCH 1/9] pki: Load dnskey plugin to encode public keys in RFC 3110 format --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 2d1762c77..6af8b535d 100644 --- a/configure.ac +++ b/configure.ac @@ -1008,7 +1008,7 @@ ADD_PLUGIN([pkcs7], [s charon scepclient pki scripts nm cmd]) ADD_PLUGIN([pkcs8], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) ADD_PLUGIN([pkcs12], [s charon scepclient pki scripts cmd]) ADD_PLUGIN([pgp], [s charon]) -ADD_PLUGIN([dnskey], [s charon]) +ADD_PLUGIN([dnskey], [s charon pki]) ADD_PLUGIN([sshkey], [s charon nm cmd]) ADD_PLUGIN([ipseckey], [c charon]) ADD_PLUGIN([pem], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) From b5cc7053c83285181b0ee7ea0f13bed3431d9fd0 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 15 Aug 2013 12:29:06 +0200 Subject: [PATCH 2/9] openssl: Add helper function to convert BIGNUMs to chunks --- .../plugins/openssl/openssl_util.c | 18 ++++++++++++++++++ .../plugins/openssl/openssl_util.h | 9 +++++++++ 2 files changed, 27 insertions(+) diff --git a/src/libstrongswan/plugins/openssl/openssl_util.c b/src/libstrongswan/plugins/openssl/openssl_util.c index bc10dd28c..0e61086b1 100644 --- a/src/libstrongswan/plugins/openssl/openssl_util.c +++ b/src/libstrongswan/plugins/openssl/openssl_util.c @@ -123,6 +123,24 @@ bool openssl_bn_split(chunk_t chunk, BIGNUM *a, BIGNUM *b) return TRUE; } +/** + * Described in header. + */ +bool openssl_bn2chunk(BIGNUM *bn, chunk_t *chunk) +{ + *chunk = chunk_alloc(BN_num_bytes(bn)); + if (BN_bn2bin(bn, chunk->ptr) == chunk->len) + { + if (chunk->len && chunk->ptr[0] & 0x80) + { /* if MSB is set, prepend a zero to make it non-negative */ + *chunk = chunk_cat("cm", chunk_from_chars(0x00), *chunk); + } + return TRUE; + } + chunk_free(chunk); + return FALSE; +} + /** * Described in header. */ diff --git a/src/libstrongswan/plugins/openssl/openssl_util.h b/src/libstrongswan/plugins/openssl/openssl_util.h index 25c692a1a..ce2a9e109 100644 --- a/src/libstrongswan/plugins/openssl/openssl_util.h +++ b/src/libstrongswan/plugins/openssl/openssl_util.h @@ -66,6 +66,15 @@ bool openssl_bn_cat(int len, BIGNUM *a, BIGNUM *b, chunk_t *chunk); */ bool openssl_bn_split(chunk_t chunk, BIGNUM *a, BIGNUM *b); +/** + * Exports the given bignum (assumed to be a positive number) to a chunk in + * two's complement format (i.e. a zero byte is added if the MSB is set). + * + * @param bn the BIGNUM to export + * @param chunk the chunk (data gets allocated) + * @return TRUE on success, FALSE otherwise + */ +bool openssl_bn2chunk(BIGNUM *bn, chunk_t *chunk); /** * Allocate a chunk using the i2d function of a given object From 3b939e20a96984584a941da452513220ef0c38af Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 14 Aug 2013 18:23:00 +0200 Subject: [PATCH 3/9] openssl: Add generic RSA public key encoding --- .../plugins/openssl/openssl_rsa_public_key.c | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index 48beedef6..f0c172629 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -19,6 +19,7 @@ #ifndef OPENSSL_NO_RSA #include "openssl_rsa_public_key.h" +#include "openssl_util.h" #include @@ -248,6 +249,7 @@ METHOD(public_key_t, get_encoding, bool, private_openssl_rsa_public_key_t *this, cred_encoding_type_t type, chunk_t *encoding) { + bool success = FALSE; u_char *p; switch (type) @@ -255,11 +257,10 @@ METHOD(public_key_t, get_encoding, bool, case PUBKEY_SPKI_ASN1_DER: case PUBKEY_PEM: { - bool success = TRUE; - *encoding = chunk_alloc(i2d_RSA_PUBKEY(this->rsa, NULL)); p = encoding->ptr; i2d_RSA_PUBKEY(this->rsa, &p); + success = TRUE; if (type == PUBKEY_PEM) { @@ -280,7 +281,20 @@ METHOD(public_key_t, get_encoding, bool, return TRUE; } default: - return FALSE; + { + chunk_t n = chunk_empty, e = chunk_empty; + + if (openssl_bn2chunk(this->rsa->n, &n) && + openssl_bn2chunk(this->rsa->e, &e)) + { + success = lib->encoding->encode(lib->encoding, type, NULL, + encoding, CRED_PART_RSA_MODULUS, n, + CRED_PART_RSA_PUB_EXP, e, CRED_PART_END); + } + chunk_free(&n); + chunk_free(&e); + return success; + } } } From f40e9f4d161d79a5e4c93c4b0423c6535b9553f9 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 15 Aug 2013 12:42:09 +0200 Subject: [PATCH 4/9] sshkey: Add encoder for RSA keys --- src/libstrongswan/credentials/cred_encoding.h | 2 + src/libstrongswan/plugins/sshkey/Makefile.am | 3 +- .../plugins/sshkey/sshkey_builder.h | 2 +- .../plugins/sshkey/sshkey_encoder.c | 53 +++++++++++++++++++ .../plugins/sshkey/sshkey_encoder.h | 32 +++++++++++ .../plugins/sshkey/sshkey_plugin.c | 3 ++ 6 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 src/libstrongswan/plugins/sshkey/sshkey_encoder.c create mode 100644 src/libstrongswan/plugins/sshkey/sshkey_encoder.h diff --git a/src/libstrongswan/credentials/cred_encoding.h b/src/libstrongswan/credentials/cred_encoding.h index 41481f376..27a887f27 100644 --- a/src/libstrongswan/credentials/cred_encoding.h +++ b/src/libstrongswan/credentials/cred_encoding.h @@ -87,6 +87,8 @@ enum cred_encoding_type_t { PRIVKEY_PGP, /** DNSKEY encoding */ PUBKEY_DNSKEY, + /** SSHKEY encoding (Base64) */ + PUBKEY_SSHKEY, /** ASN.1 DER encoded certificate */ CERT_ASN1_DER, diff --git a/src/libstrongswan/plugins/sshkey/Makefile.am b/src/libstrongswan/plugins/sshkey/Makefile.am index d2ec631a8..22c076f84 100644 --- a/src/libstrongswan/plugins/sshkey/Makefile.am +++ b/src/libstrongswan/plugins/sshkey/Makefile.am @@ -12,6 +12,7 @@ endif libstrongswan_sshkey_la_SOURCES = \ sshkey_plugin.h sshkey_plugin.c \ - sshkey_builder.h sshkey_builder.c + sshkey_builder.h sshkey_builder.c \ + sshkey_encoder.h sshkey_encoder.c libstrongswan_sshkey_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/sshkey/sshkey_builder.h b/src/libstrongswan/plugins/sshkey/sshkey_builder.h index e4c7a90d0..d138c879b 100644 --- a/src/libstrongswan/plugins/sshkey/sshkey_builder.h +++ b/src/libstrongswan/plugins/sshkey/sshkey_builder.h @@ -14,7 +14,7 @@ */ /** - * @defgroup sshky_public_key sshky_public_key + * @defgroup sshkey_public_key sshkey_public_key * @{ @ingroup sshkey_p */ diff --git a/src/libstrongswan/plugins/sshkey/sshkey_encoder.c b/src/libstrongswan/plugins/sshkey/sshkey_encoder.c new file mode 100644 index 000000000..8f0cb6b63 --- /dev/null +++ b/src/libstrongswan/plugins/sshkey/sshkey_encoder.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "sshkey_encoder.h" + +#include + +/** + * Encode the public key as Base64 encoded SSH key blob + */ +static bool build_public_key(chunk_t *encoding, va_list args) +{ + bio_writer_t *writer; + chunk_t n, e; + + if (cred_encoding_args(args, CRED_PART_RSA_MODULUS, &n, + CRED_PART_RSA_PUB_EXP, &e, CRED_PART_END)) + { + writer = bio_writer_create(0); + writer->write_data32(writer, chunk_from_str("ssh-rsa")); + + writer->write_data32(writer, e); + writer->write_data32(writer, n); + *encoding = chunk_to_base64(writer->get_buf(writer), NULL); + writer->destroy(writer); + return TRUE; + } + return FALSE; +} + +bool sshkey_encoder_encode(cred_encoding_type_t type, chunk_t *encoding, + va_list args) +{ + switch (type) + { + case PUBKEY_SSHKEY: + return build_public_key(encoding, args); + default: + return FALSE; + } +} diff --git a/src/libstrongswan/plugins/sshkey/sshkey_encoder.h b/src/libstrongswan/plugins/sshkey/sshkey_encoder.h new file mode 100644 index 000000000..bdd31a6c8 --- /dev/null +++ b/src/libstrongswan/plugins/sshkey/sshkey_encoder.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup sshkey_encoder sshkey_encoder + * @{ @ingroup sshkey_p + */ + +#ifndef SSHKEY_ENCODER_H_ +#define SSHKEY_ENCODER_H_ + +#include + +/** + * Encoding of public keys to RFC 4253 format. + */ +bool sshkey_encoder_encode(cred_encoding_type_t type, chunk_t *encoding, + va_list args); + +#endif /** SSHKEY_ENCODER_H_ @}*/ diff --git a/src/libstrongswan/plugins/sshkey/sshkey_plugin.c b/src/libstrongswan/plugins/sshkey/sshkey_plugin.c index fe6252671..6409feaf1 100644 --- a/src/libstrongswan/plugins/sshkey/sshkey_plugin.c +++ b/src/libstrongswan/plugins/sshkey/sshkey_plugin.c @@ -17,6 +17,7 @@ #include #include "sshkey_builder.h" +#include "sshkey_encoder.h" typedef struct private_sshkey_plugin_t private_sshkey_plugin_t; @@ -51,6 +52,7 @@ METHOD(plugin_t, get_features, int, METHOD(plugin_t, destroy, void, private_sshkey_plugin_t *this) { + lib->encoding->remove_encoder(lib->encoding, sshkey_encoder_encode); free(this); } @@ -70,6 +72,7 @@ plugin_t *sshkey_plugin_create() }, }, ); + lib->encoding->add_encoder(lib->encoding, sshkey_encoder_encode); return &this->public.plugin; } From 21626bdf77957d60631fe939fc00f77c4a429f75 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 15 Aug 2013 12:43:01 +0200 Subject: [PATCH 5/9] pki: Add support to encode public keys in SSH key format --- configure.ac | 2 +- src/pki/commands/pub.c | 2 +- src/pki/man/pki---pub.1.in | 5 +++-- src/pki/pki.c | 13 ++++++++++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 6af8b535d..3dbeeccee 100644 --- a/configure.ac +++ b/configure.ac @@ -1009,7 +1009,7 @@ ADD_PLUGIN([pkcs8], [s charon openac scepclient pki scripts manag ADD_PLUGIN([pkcs12], [s charon scepclient pki scripts cmd]) ADD_PLUGIN([pgp], [s charon]) ADD_PLUGIN([dnskey], [s charon pki]) -ADD_PLUGIN([sshkey], [s charon nm cmd]) +ADD_PLUGIN([sshkey], [s charon pki nm cmd]) ADD_PLUGIN([ipseckey], [c charon]) ADD_PLUGIN([pem], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) ADD_PLUGIN([padlock], [s charon]) diff --git a/src/pki/commands/pub.c b/src/pki/commands/pub.c index 5a658afec..d85ee9ff3 100644 --- a/src/pki/commands/pub.c +++ b/src/pki/commands/pub.c @@ -158,7 +158,7 @@ static void __attribute__ ((constructor))reg() pub, 'p', "pub", "extract the public key from a private key/certificate", {"[--in file|--keyid hex] [--type rsa|ecdsa|pkcs10|x509]", - "[--outform der|pem|dnskey]"}, + "[--outform der|pem|dnskey|sshkey]"}, { {"help", 'h', 0, "show usage information"}, {"in", 'i', 1, "input file, default: stdin"}, diff --git a/src/pki/man/pki---pub.1.in b/src/pki/man/pki---pub.1.in index d588ae732..a1b9b0ad4 100644 --- a/src/pki/man/pki---pub.1.in +++ b/src/pki/man/pki---pub.1.in @@ -53,7 +53,8 @@ certificate), defaults to \fIrsa\fR. .TP .BI "\-f, \-\-outform " encoding Encoding of the extracted public key. One of \fIder\fR (ASN.1 DER), \fIpem\fR -(Base64 PEM), or \fIdnskey\fR (RFC 3110 DNS key), defaults to \fIder\fR. +(Base64 PEM), \fIdnskey\fR (RFC 3110 DNS key), or \fIsshkey\fR (RFC 4253 SSH +key), defaults to \fIder\fR. . .SH "EXAMPLES" . @@ -72,4 +73,4 @@ Extract the public key from an X.509 certificate: . .SH "SEE ALSO" . -.BR pki (1) \ No newline at end of file +.BR pki (1) diff --git a/src/pki/pki.c b/src/pki/pki.c index c3039a649..ecc0702cd 100644 --- a/src/pki/pki.c +++ b/src/pki/pki.c @@ -81,7 +81,18 @@ bool get_form(char *form, cred_encoding_type_t *enc, credential_type_t type) switch (type) { case CRED_PUBLIC_KEY: - *enc =PUBKEY_DNSKEY; + *enc = PUBKEY_DNSKEY; + return TRUE; + default: + return FALSE; + } + } + else if (streq(form, "sshkey")) + { + switch (type) + { + case CRED_PUBLIC_KEY: + *enc = PUBKEY_SSHKEY; return TRUE; default: return FALSE; From 90afd2c9290b3b0bd605444d58c271a15b6df2b3 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 15 Aug 2013 12:43:30 +0200 Subject: [PATCH 6/9] pki: --pub also accepts public keys (i.e. to convert them to a different format) --- src/pki/commands/pub.c | 16 +++++++++++++++- src/pki/man/pki---pub.1.in | 5 +++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/pki/commands/pub.c b/src/pki/commands/pub.c index d85ee9ff3..537af5159 100644 --- a/src/pki/commands/pub.c +++ b/src/pki/commands/pub.c @@ -51,6 +51,11 @@ static int pub() type = CRED_PRIVATE_KEY; subtype = KEY_ECDSA; } + else if (streq(arg, "pub")) + { + type = CRED_PUBLIC_KEY; + subtype = KEY_ANY; + } else if (streq(arg, "pkcs10")) { type = CRED_CERTIFICATE; @@ -116,6 +121,15 @@ static int pub() public = private->get_public_key(private); private->destroy(private); } + else if (type == CRED_PUBLIC_KEY) + { + public = cred; + if (!public) + { + fprintf(stderr, "parsing public key failed\n"); + return 1; + } + } else { cert = cred; @@ -157,7 +171,7 @@ static void __attribute__ ((constructor))reg() command_register((command_t) { pub, 'p', "pub", "extract the public key from a private key/certificate", - {"[--in file|--keyid hex] [--type rsa|ecdsa|pkcs10|x509]", + {"[--in file|--keyid hex] [--type rsa|ecdsa|pub|pkcs10|x509]", "[--outform der|pem|dnskey|sshkey]"}, { {"help", 'h', 0, "show usage information"}, diff --git a/src/pki/man/pki---pub.1.in b/src/pki/man/pki---pub.1.in index a1b9b0ad4..c57e03a40 100644 --- a/src/pki/man/pki---pub.1.in +++ b/src/pki/man/pki---pub.1.in @@ -48,8 +48,9 @@ Input file. If not given the input is read from \fISTDIN\fR. .TP .BI "\-t, \-\-type " type Type of input. One of \fIrsa\fR (RSA private key), \fIecdsa\fR (ECDSA -private key), \fIpkcs10\fR (PKCS#10 certificate request), \fIx509\fR (X.509 -certificate), defaults to \fIrsa\fR. +private key), \fIpub\fR (public key), +\fIpkcs10\fR (PKCS#10 certificate request), or \fIx509\fR (X.509 certificate), +defaults to \fIrsa\fR. .TP .BI "\-f, \-\-outform " encoding Encoding of the extracted public key. One of \fIder\fR (ASN.1 DER), \fIpem\fR From d6b3cc87ca22b4829098685517e5b03d114cad54 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 16 Aug 2013 13:12:47 +0200 Subject: [PATCH 7/9] openssl: Add support for generic encoding of EC public keys --- .../plugins/openssl/openssl_ec_public_key.c | 34 +++++++------------ 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c index 38cc8bedf..382c55418 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c @@ -245,33 +245,23 @@ METHOD(public_key_t, get_encoding, bool, private_openssl_ec_public_key_t *this, cred_encoding_type_t type, chunk_t *encoding) { + bool success = TRUE; u_char *p; - switch (type) + *encoding = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL)); + p = encoding->ptr; + i2d_EC_PUBKEY(this->ec, &p); + + if (type != PUBKEY_SPKI_ASN1_DER) { - case PUBKEY_SPKI_ASN1_DER: - case PUBKEY_PEM: - { - bool success = TRUE; + chunk_t asn1_encoding = *encoding; - *encoding = chunk_alloc(i2d_EC_PUBKEY(this->ec, NULL)); - p = encoding->ptr; - i2d_EC_PUBKEY(this->ec, &p); - - if (type == PUBKEY_PEM) - { - chunk_t asn1_encoding = *encoding; - - success = lib->encoding->encode(lib->encoding, PUBKEY_PEM, - NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER, - asn1_encoding, CRED_PART_END); - chunk_clear(&asn1_encoding); - } - return success; - } - default: - return FALSE; + success = lib->encoding->encode(lib->encoding, type, + NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER, + asn1_encoding, CRED_PART_END); + chunk_clear(&asn1_encoding); } + return success; } METHOD(public_key_t, get_ref, public_key_t*, From b2a5317596c0349454942dcd5cc36849081116be Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 16 Aug 2013 13:13:49 +0200 Subject: [PATCH 8/9] sshkey: Add encoding for ECDSA keys --- .../plugins/sshkey/sshkey_encoder.c | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/libstrongswan/plugins/sshkey/sshkey_encoder.c b/src/libstrongswan/plugins/sshkey/sshkey_encoder.c index 8f0cb6b63..d423671bd 100644 --- a/src/libstrongswan/plugins/sshkey/sshkey_encoder.c +++ b/src/libstrongswan/plugins/sshkey/sshkey_encoder.c @@ -15,8 +15,43 @@ #include "sshkey_encoder.h" +#include +#include #include +#define ECDSA_PREFIX "ecdsa-sha2-" + +/** + * Write an EC domain parameter identifier as defined in RFC 5656 + */ +static void write_ec_identifier(bio_writer_t *writer, char *prefix, int oid, + chunk_t enc) +{ + char *curve, identifier[128]; + + switch (oid) + { + case OID_PRIME256V1: + curve = strdup("nistp256"); + break; + case OID_SECT384R1: + curve = strdup("nistp384"); + break; + case OID_SECT521R1: + curve = strdup("nistp521"); + break; + default: + curve = asn1_oid_to_string(enc); + break; + } + if (curve && snprintf(identifier, sizeof(identifier), "%s%s", prefix, + curve) < sizeof(identifier)) + { + writer->write_data32(writer, chunk_from_str(identifier)); + } + free(curve); +} + /** * Encode the public key as Base64 encoded SSH key blob */ @@ -37,6 +72,43 @@ static bool build_public_key(chunk_t *encoding, va_list args) writer->destroy(writer); return TRUE; } + else if (cred_encoding_args(args, CRED_PART_ECDSA_PUB_ASN1_DER, &n, + CRED_PART_END)) + { + chunk_t params, alg, q; + int oid; + + /* parse subjectPublicKeyInfo */ + if (asn1_unwrap(&n, &n) != ASN1_SEQUENCE) + { + return FALSE; + } + oid = asn1_parse_algorithmIdentifier(n, 1, ¶ms); + if (oid != OID_EC_PUBLICKEY || + asn1_unwrap(¶ms, ¶ms) != ASN1_OID) + { + return FALSE; + } + oid = asn1_known_oid(params); + if (oid == OID_UNKNOWN) + { + return FALSE; + } + if (asn1_unwrap(&n, &alg) != ASN1_SEQUENCE || + asn1_unwrap(&n, &q) != ASN1_BIT_STRING) + { + return FALSE; + } + writer = bio_writer_create(0); + write_ec_identifier(writer, ECDSA_PREFIX, oid, params); + write_ec_identifier(writer, "", oid, params); + + q = chunk_skip_zero(q); + writer->write_data32(writer, q); + *encoding = chunk_to_base64(writer->get_buf(writer), NULL); + writer->destroy(writer); + return TRUE; + } return FALSE; } From 075e80368bed1c72cd5814540598f54bcb03b13a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 19 Aug 2013 13:15:28 +0200 Subject: [PATCH 9/9] sshkey: Add support for parsing keys from files --- .../plugins/sshkey/sshkey_builder.c | 93 ++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/src/libstrongswan/plugins/sshkey/sshkey_builder.c b/src/libstrongswan/plugins/sshkey/sshkey_builder.c index d6a7c645a..61e829fdf 100644 --- a/src/libstrongswan/plugins/sshkey/sshkey_builder.c +++ b/src/libstrongswan/plugins/sshkey/sshkey_builder.c @@ -13,6 +13,10 @@ * for more details. */ +#include +#include +#include + #include "sshkey_builder.h" #include @@ -124,12 +128,85 @@ static sshkey_public_key_t *parse_public_key(chunk_t blob) return NULL; } +/** + * Load SSH key from a FILE stream, closes the stream + */ +static sshkey_public_key_t *load_from_stream(FILE *file) +{ + sshkey_public_key_t *public = NULL; + chunk_t blob = chunk_empty; + enumerator_t *enumerator; + char line[1024], *token; + + while (!public && fgets(line, sizeof(line), file)) + { /* the format is: ssh-[rsa|ecdsa-...] */ + if (!strpfx(line, "ssh-")) + { + continue; + } + enumerator = enumerator_create_token(line, " ", " "); + if (enumerator->enumerate(enumerator, &token) && + enumerator->enumerate(enumerator, &token)) + { + blob = chunk_from_base64(chunk_from_str(token), NULL); + } + enumerator->destroy(enumerator); + if (blob.ptr) + { + public = parse_public_key(blob); + chunk_free(&blob); + } + } + fclose(file); + return public; +} + +/** + * Load SSH key from FD + */ +static sshkey_public_key_t *load_from_fd(int fd) +{ + FILE *stream; + + /* dup the FD as it gets closed in fclose() */ + fd = dup(fd); + if (fd == -1) + { + return NULL; + } + stream = fdopen(fd, "r"); + if (!stream) + { + close(fd); + return NULL; + } + return load_from_stream(stream); +} + +/** + * Load SSH key from file + */ +static sshkey_public_key_t *load_from_file(char *file) +{ + FILE *stream; + + stream = fopen(file, "r"); + if (!stream) + { + DBG1(DBG_LIB, " opening '%s' failed: %s", file, strerror(errno)); + return NULL; + } + return load_from_stream(stream); +} + /** * See header. */ sshkey_public_key_t *sshkey_public_key_load(key_type_t type, va_list args) { chunk_t blob = chunk_empty; + char *file = NULL; + int fd = -1; while (TRUE) { @@ -138,6 +215,12 @@ sshkey_public_key_t *sshkey_public_key_load(key_type_t type, va_list args) case BUILD_BLOB_SSHKEY: blob = va_arg(args, chunk_t); continue; + case BUILD_FROM_FILE: + file = va_arg(args, char*); + continue; + case BUILD_FROM_FD: + fd = va_arg(args, int); + continue; case BUILD_END: break; default: @@ -145,9 +228,17 @@ sshkey_public_key_t *sshkey_public_key_load(key_type_t type, va_list args) } break; } - if (blob.ptr && type == KEY_ANY) + if (blob.ptr) { return parse_public_key(blob); } + if (file) + { + return load_from_file(file); + } + if (fd != -1) + { + return load_from_fd(fd); + } return NULL; }