sshkey: Add encoding for ECDSA keys
[strongswan.git] / src / libstrongswan / plugins / sshkey / sshkey_encoder.c
1 /*
2 * Copyright (C) 2013 Tobias Brunner
3 * 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 #include "sshkey_encoder.h"
17
18 #include <asn1/asn1.h>
19 #include <asn1/oid.h>
20 #include <bio/bio_writer.h>
21
22 #define ECDSA_PREFIX "ecdsa-sha2-"
23
24 /**
25 * Write an EC domain parameter identifier as defined in RFC 5656
26 */
27 static void write_ec_identifier(bio_writer_t *writer, char *prefix, int oid,
28 chunk_t enc)
29 {
30 char *curve, identifier[128];
31
32 switch (oid)
33 {
34 case OID_PRIME256V1:
35 curve = strdup("nistp256");
36 break;
37 case OID_SECT384R1:
38 curve = strdup("nistp384");
39 break;
40 case OID_SECT521R1:
41 curve = strdup("nistp521");
42 break;
43 default:
44 curve = asn1_oid_to_string(enc);
45 break;
46 }
47 if (curve && snprintf(identifier, sizeof(identifier), "%s%s", prefix,
48 curve) < sizeof(identifier))
49 {
50 writer->write_data32(writer, chunk_from_str(identifier));
51 }
52 free(curve);
53 }
54
55 /**
56 * Encode the public key as Base64 encoded SSH key blob
57 */
58 static bool build_public_key(chunk_t *encoding, va_list args)
59 {
60 bio_writer_t *writer;
61 chunk_t n, e;
62
63 if (cred_encoding_args(args, CRED_PART_RSA_MODULUS, &n,
64 CRED_PART_RSA_PUB_EXP, &e, CRED_PART_END))
65 {
66 writer = bio_writer_create(0);
67 writer->write_data32(writer, chunk_from_str("ssh-rsa"));
68
69 writer->write_data32(writer, e);
70 writer->write_data32(writer, n);
71 *encoding = chunk_to_base64(writer->get_buf(writer), NULL);
72 writer->destroy(writer);
73 return TRUE;
74 }
75 else if (cred_encoding_args(args, CRED_PART_ECDSA_PUB_ASN1_DER, &n,
76 CRED_PART_END))
77 {
78 chunk_t params, alg, q;
79 int oid;
80
81 /* parse subjectPublicKeyInfo */
82 if (asn1_unwrap(&n, &n) != ASN1_SEQUENCE)
83 {
84 return FALSE;
85 }
86 oid = asn1_parse_algorithmIdentifier(n, 1, &params);
87 if (oid != OID_EC_PUBLICKEY ||
88 asn1_unwrap(&params, &params) != ASN1_OID)
89 {
90 return FALSE;
91 }
92 oid = asn1_known_oid(params);
93 if (oid == OID_UNKNOWN)
94 {
95 return FALSE;
96 }
97 if (asn1_unwrap(&n, &alg) != ASN1_SEQUENCE ||
98 asn1_unwrap(&n, &q) != ASN1_BIT_STRING)
99 {
100 return FALSE;
101 }
102 writer = bio_writer_create(0);
103 write_ec_identifier(writer, ECDSA_PREFIX, oid, params);
104 write_ec_identifier(writer, "", oid, params);
105
106 q = chunk_skip_zero(q);
107 writer->write_data32(writer, q);
108 *encoding = chunk_to_base64(writer->get_buf(writer), NULL);
109 writer->destroy(writer);
110 return TRUE;
111 }
112 return FALSE;
113 }
114
115 bool sshkey_encoder_encode(cred_encoding_type_t type, chunk_t *encoding,
116 va_list args)
117 {
118 switch (type)
119 {
120 case PUBKEY_SSHKEY:
121 return build_public_key(encoding, args);
122 default:
123 return FALSE;
124 }
125 }