summaryrefslogtreecommitdiff
path: root/sshkey.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2020-04-08 00:01:52 +0000
committerDamien Miller <djm@mindrot.org>2020-04-08 10:14:21 +1000
commitc0f5b2294796451001fd328c44f0d00f1114eddf (patch)
treec5ca6f4e3ea8fbba8e68cce80758281c3f2b487b /sshkey.c
parent8461a5b3db34ed0b5a4a18d82f64fd5ac8693ea8 (diff)
upstream: refactor private key parsing a little
Split out the base64 decoding and private section decryption steps in to separate functions. This will make the decryption step easier to fuzz as well as making it easier to write a "load public key from new-format private key" function. ok markus@ OpenBSD-Commit-ID: 7de31d80fb9062aa01901ddf040c286b64ff904e
Diffstat (limited to 'sshkey.c')
-rw-r--r--sshkey.c154
1 files changed, 114 insertions, 40 deletions
diff --git a/sshkey.c b/sshkey.c
index 6eba16ecf..0fc0f97ca 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshkey.c,v 1.102 2020/03/06 18:23:17 markus Exp $ */ 1/* $OpenBSD: sshkey.c,v 1.103 2020/04/08 00:01:52 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
4 * Copyright (c) 2008 Alexander von Gernler. All rights reserved. 4 * Copyright (c) 2008 Alexander von Gernler. All rights reserved.
@@ -4060,30 +4060,21 @@ sshkey_private_to_blob2(struct sshkey *prv, struct sshbuf *blob,
4060} 4060}
4061 4061
4062static int 4062static int
4063sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, 4063private2_uudecode(struct sshbuf *blob, struct sshbuf **decodedp)
4064 struct sshkey **keyp, char **commentp)
4065{ 4064{
4066 char *comment = NULL, *ciphername = NULL, *kdfname = NULL;
4067 const struct sshcipher *cipher = NULL;
4068 const u_char *cp; 4065 const u_char *cp;
4069 int r = SSH_ERR_INTERNAL_ERROR;
4070 size_t encoded_len; 4066 size_t encoded_len;
4071 size_t i, keylen = 0, ivlen = 0, authlen = 0, slen = 0; 4067 int r;
4068 u_char last;
4072 struct sshbuf *encoded = NULL, *decoded = NULL; 4069 struct sshbuf *encoded = NULL, *decoded = NULL;
4073 struct sshbuf *kdf = NULL, *decrypted = NULL;
4074 struct sshcipher_ctx *ciphercontext = NULL;
4075 struct sshkey *k = NULL;
4076 u_char *key = NULL, *salt = NULL, *dp, pad, last;
4077 u_int blocksize, rounds, nkeys, encrypted_len, check1, check2;
4078 4070
4079 if (keyp != NULL) 4071 if (blob == NULL || decodedp == NULL)
4080 *keyp = NULL; 4072 return SSH_ERR_INVALID_ARGUMENT;
4081 if (commentp != NULL) 4073
4082 *commentp = NULL; 4074 *decodedp = NULL;
4083 4075
4084 if ((encoded = sshbuf_new()) == NULL || 4076 if ((encoded = sshbuf_new()) == NULL ||
4085 (decoded = sshbuf_new()) == NULL || 4077 (decoded = sshbuf_new()) == NULL) {
4086 (decrypted = sshbuf_new()) == NULL) {
4087 r = SSH_ERR_ALLOC_FAIL; 4078 r = SSH_ERR_ALLOC_FAIL;
4088 goto out; 4079 goto out;
4089 } 4080 }
@@ -4133,13 +4124,54 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
4133 r = SSH_ERR_INVALID_FORMAT; 4124 r = SSH_ERR_INVALID_FORMAT;
4134 goto out; 4125 goto out;
4135 } 4126 }
4127 /* success */
4128 *decodedp = decoded;
4129 decoded = NULL;
4130 r = 0;
4131 out:
4132 sshbuf_free(encoded);
4133 sshbuf_free(decoded);
4134 return r;
4135}
4136
4137static int
4138private2_decrypt(struct sshbuf *decoded, struct sshbuf **decryptedp,
4139 const char *passphrase)
4140{
4141 char *ciphername = NULL, *kdfname = NULL;
4142 const struct sshcipher *cipher = NULL;
4143 int r = SSH_ERR_INTERNAL_ERROR;
4144 size_t keylen = 0, ivlen = 0, authlen = 0, slen = 0;
4145 struct sshbuf *kdf = NULL, *decrypted = NULL;
4146 struct sshcipher_ctx *ciphercontext = NULL;
4147 u_char *key = NULL, *salt = NULL, *dp;
4148 u_int blocksize, rounds, nkeys, encrypted_len, check1, check2;
4149
4150 if (decoded == NULL || decryptedp == NULL)
4151 return SSH_ERR_INVALID_ARGUMENT;
4152
4153 *decryptedp = NULL;
4154
4155 if ((decrypted = sshbuf_new()) == NULL) {
4156 r = SSH_ERR_ALLOC_FAIL;
4157 goto out;
4158 }
4159
4136 /* parse public portion of key */ 4160 /* parse public portion of key */
4137 if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 || 4161 if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 ||
4138 (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 || 4162 (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 ||
4139 (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 || 4163 (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 ||
4140 (r = sshbuf_froms(decoded, &kdf)) != 0 || 4164 (r = sshbuf_froms(decoded, &kdf)) != 0 ||
4141 (r = sshbuf_get_u32(decoded, &nkeys)) != 0 || 4165 (r = sshbuf_get_u32(decoded, &nkeys)) != 0)
4142 (r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */ 4166 goto out;
4167
4168 if (nkeys != 1) {
4169 /* XXX only one key supported at present */
4170 r = SSH_ERR_INVALID_FORMAT;
4171 goto out;
4172 }
4173
4174 if ((r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */
4143 (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0) 4175 (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0)
4144 goto out; 4176 goto out;
4145 4177
@@ -4161,11 +4193,6 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
4161 r = SSH_ERR_KEY_WRONG_PASSPHRASE; 4193 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
4162 goto out; 4194 goto out;
4163 } 4195 }
4164 if (nkeys != 1) {
4165 /* XXX only one key supported */
4166 r = SSH_ERR_INVALID_FORMAT;
4167 goto out;
4168 }
4169 4196
4170 /* check size of encrypted key blob */ 4197 /* check size of encrypted key blob */
4171 blocksize = cipher_blocksize(cipher); 4198 blocksize = cipher_blocksize(cipher);
@@ -4228,13 +4255,35 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
4228 r = SSH_ERR_KEY_WRONG_PASSPHRASE; 4255 r = SSH_ERR_KEY_WRONG_PASSPHRASE;
4229 goto out; 4256 goto out;
4230 } 4257 }
4258 /* success */
4259 *decryptedp = decrypted;
4260 decrypted = NULL;
4261 r = 0;
4262 out:
4263 cipher_free(ciphercontext);
4264 free(ciphername);
4265 free(kdfname);
4266 if (salt != NULL) {
4267 explicit_bzero(salt, slen);
4268 free(salt);
4269 }
4270 if (key != NULL) {
4271 explicit_bzero(key, keylen + ivlen);
4272 free(key);
4273 }
4274 sshbuf_free(kdf);
4275 sshbuf_free(decrypted);
4276 return r;
4277}
4231 4278
4232 /* Load the private key and comment */ 4279/* Check deterministic padding after private key */
4233 if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 || 4280static int
4234 (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0) 4281private2_check_padding(struct sshbuf *decrypted)
4235 goto out; 4282{
4283 u_char pad;
4284 size_t i;
4285 int r = SSH_ERR_INTERNAL_ERROR;
4236 4286
4237 /* Check deterministic padding */
4238 i = 0; 4287 i = 0;
4239 while (sshbuf_len(decrypted)) { 4288 while (sshbuf_len(decrypted)) {
4240 if ((r = sshbuf_get_u8(decrypted, &pad)) != 0) 4289 if ((r = sshbuf_get_u8(decrypted, &pad)) != 0)
@@ -4244,6 +4293,41 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
4244 goto out; 4293 goto out;
4245 } 4294 }
4246 } 4295 }
4296 /* success */
4297 r = 0;
4298 out:
4299 explicit_bzero(&pad, sizeof(pad));
4300 explicit_bzero(&i, sizeof(i));
4301 return r;
4302}
4303
4304static int
4305sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
4306 struct sshkey **keyp, char **commentp)
4307{
4308 char *comment = NULL;
4309 int r = SSH_ERR_INTERNAL_ERROR;
4310 struct sshbuf *decoded = NULL, *decrypted = NULL;
4311 struct sshkey *k = NULL;
4312
4313 if (keyp != NULL)
4314 *keyp = NULL;
4315 if (commentp != NULL)
4316 *commentp = NULL;
4317
4318 /* Undo base64 encoding and decrypt the private section */
4319 if ((r = private2_uudecode(blob, &decoded)) != 0 ||
4320 (r = private2_decrypt(decoded, &decrypted, passphrase)) != 0)
4321 goto out;
4322
4323 /* Load the private key and comment */
4324 if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 ||
4325 (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0)
4326 goto out;
4327
4328 /* Check deterministic padding after private section */
4329 if ((r = private2_check_padding(decrypted)) != 0)
4330 goto out;
4247 4331
4248 /* XXX decode pubkey and check against private */ 4332 /* XXX decode pubkey and check against private */
4249 4333
@@ -4258,18 +4342,8 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
4258 comment = NULL; 4342 comment = NULL;
4259 } 4343 }
4260 out: 4344 out:
4261 pad = 0;
4262 cipher_free(ciphercontext);
4263 free(ciphername);
4264 free(kdfname);
4265 free(comment); 4345 free(comment);
4266 if (salt != NULL)
4267 freezero(salt, slen);
4268 if (key != NULL)
4269 freezero(key, keylen + ivlen);
4270 sshbuf_free(encoded);
4271 sshbuf_free(decoded); 4346 sshbuf_free(decoded);
4272 sshbuf_free(kdf);
4273 sshbuf_free(decrypted); 4347 sshbuf_free(decrypted);
4274 sshkey_free(k); 4348 sshkey_free(k);
4275 return r; 4349 return r;