summaryrefslogtreecommitdiff
path: root/sshkey.c
diff options
context:
space:
mode:
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;