[authfile.c authfile.h cipher.c cipher.h key.c packet.c ssh-agent.c]
     [ssh-keygen.c PROTOCOL.key] new private key format, bcrypt as KDF by
     default; details in PROTOCOL.key; feedback and lots help from djm;
     ok djm@
This commit is contained in:
Damien Miller 2013-12-07 10:41:55 +11:00
parent f0e9060d23
commit bcd00abd84
10 changed files with 505 additions and 50 deletions

View File

@ -12,6 +12,11 @@
- markus@cvs.openbsd.org 2013/12/06 13:30:08
[authfd.c key.c key.h ssh-agent.c]
move private key (de)serialization to key.c; ok djm
- markus@cvs.openbsd.org 2013/12/06 13:34:54
[authfile.c authfile.h cipher.c cipher.h key.c packet.c ssh-agent.c]
[ssh-keygen.c PROTOCOL.key] new private key format, bcrypt as KDF by
default; details in PROTOCOL.key; feedback and lots help from djm;
ok djm@
20131205
- (djm) OpenBSD CVS Sync

68
PROTOCOL.key Normal file
View File

@ -0,0 +1,68 @@
This document describes the private key format for OpenSSH.
1. Overall format
The key consists of a header, a list of public keys, and
an encrypted list of matching private keys.
#define AUTH_MAGIC "openssh-key-v1"
byte[] AUTH_MAGIC
string ciphername
string kdfname
string kdfoptions
int number of keys N
string publickey1
string publickey2
...
string publickeyN
string encrypted, padded list of private keys
2. KDF options for kdfname "bcrypt"
The options:
string salt
uint32 rounds
are concatenated and represented as a string.
3. Unencrypted list of N private keys
The list of privatekey/comment pairs is padded with the
bytes 1, 2, 3, ... until the total length is a multiple
of the cipher block size.
uint32 checkint
uint32 checkint
string privatekey1
string comment1
string privatekey2
string comment2
...
string privatekeyN
string commentN
char 1
char 2
char 3
...
char padlen % 255
Before the key is encrypted, a random integer is assigned
to both checkint fields so successful decryption can be
quickly checked by verifying that both checkint fields
hold the same value.
4. Encryption
The KDF is used to derive a key, IV (and other values required by
the cipher) from the passphrase. These values are then used to
encrypt the unencrypted list of private keys.
5. No encryption
For unencrypted keys the cipher "none" and the KDF "none"
are used with empty passphrases. The options if the KDF "none"
are the empty string.
$OpenBSD: PROTOCOL.key,v 1.1 2013/12/06 13:34:54 markus Exp $

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfile.c,v 1.98 2013/11/21 00:45:43 djm Exp $ */
/* $OpenBSD: authfile.c,v 1.99 2013/12/06 13:34:54 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -13,7 +13,7 @@
* called by a name other than "ssh" or "Secure Shell".
*
*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -58,6 +58,8 @@
#include <string.h>
#include <unistd.h>
#include <util.h>
#include "xmalloc.h"
#include "cipher.h"
#include "buffer.h"
@ -68,6 +70,16 @@
#include "rsa.h"
#include "misc.h"
#include "atomicio.h"
#include "uuencode.h"
/* openssh private key file format */
#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n"
#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n"
#define KDFNAME "bcrypt"
#define AUTH_MAGIC "openssh-key-v1"
#define SALT_LEN 16
#define DEFAULT_CIPHERNAME "aes256-cbc"
#define DEFAULT_ROUNDS 16
#define MAX_KEY_FILE_SIZE (1024 * 1024)
@ -75,6 +87,333 @@
static const char authfile_id_string[] =
"SSH PRIVATE KEY FILE FORMAT 1.1\n";
static int
key_private_to_blob2(Key *prv, Buffer *blob, const char *passphrase,
const char *comment, const char *ciphername, int rounds)
{
u_char *key, *cp, salt[SALT_LEN];
size_t keylen, ivlen, blocksize, authlen;
u_int len, check;
int i, n;
const Cipher *c;
Buffer encoded, b, kdf;
CipherContext ctx;
const char *kdfname = KDFNAME;
if (rounds <= 0)
rounds = DEFAULT_ROUNDS;
if (passphrase == NULL || !strlen(passphrase)) {
ciphername = "none";
kdfname = "none";
} else if (ciphername == NULL)
ciphername = DEFAULT_CIPHERNAME;
else if (cipher_number(ciphername) != SSH_CIPHER_SSH2)
fatal("invalid cipher");
if ((c = cipher_by_name(ciphername)) == NULL)
fatal("unknown cipher name");
buffer_init(&kdf);
blocksize = cipher_blocksize(c);
keylen = cipher_keylen(c);
ivlen = cipher_ivlen(c);
authlen = cipher_authlen(c);
key = xcalloc(1, keylen + ivlen);
if (strcmp(kdfname, "none") != 0) {
arc4random_buf(salt, SALT_LEN);
if (bcrypt_pbkdf(passphrase, strlen(passphrase),
salt, SALT_LEN, key, keylen + ivlen, rounds) < 0)
fatal("bcrypt_pbkdf failed");
buffer_put_string(&kdf, salt, SALT_LEN);
buffer_put_int(&kdf, rounds);
}
cipher_init(&ctx, c, key, keylen, key + keylen , ivlen, 1);
memset(key, 0, keylen + ivlen);
free(key);
buffer_init(&encoded);
buffer_append(&encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC));
buffer_put_cstring(&encoded, ciphername);
buffer_put_cstring(&encoded, kdfname);
buffer_put_string(&encoded, buffer_ptr(&kdf), buffer_len(&kdf));
buffer_put_int(&encoded, 1); /* number of keys */
key_to_blob(prv, &cp, &len); /* public key */
buffer_put_string(&encoded, cp, len);
memset(cp, 0, len);
free(cp);
buffer_free(&kdf);
/* set up the buffer that will be encrypted */
buffer_init(&b);
/* Random check bytes */
check = arc4random();
buffer_put_int(&b, check);
buffer_put_int(&b, check);
/* append private key and comment*/
key_private_serialize(prv, &b);
buffer_put_cstring(&b, comment);
/* padding */
i = 0;
while (buffer_len(&b) % blocksize)
buffer_put_char(&b, ++i & 0xff);
/* length */
buffer_put_int(&encoded, buffer_len(&b));
/* encrypt */
cp = buffer_append_space(&encoded, buffer_len(&b) + authlen);
if (cipher_crypt(&ctx, 0, cp, buffer_ptr(&b), buffer_len(&b), 0,
authlen) != 0)
fatal("%s: cipher_crypt failed", __func__);
buffer_free(&b);
cipher_cleanup(&ctx);
/* uuencode */
len = 2 * buffer_len(&encoded);
cp = xmalloc(len);
n = uuencode(buffer_ptr(&encoded), buffer_len(&encoded),
(char *)cp, len);
if (n < 0)
fatal("%s: uuencode", __func__);
buffer_clear(blob);
buffer_append(blob, MARK_BEGIN, sizeof(MARK_BEGIN) - 1);
for (i = 0; i < n; i++) {
buffer_put_char(blob, cp[i]);
if (i % 70 == 69)
buffer_put_char(blob, '\n');
}
if (i % 70 != 69)
buffer_put_char(blob, '\n');
buffer_append(blob, MARK_END, sizeof(MARK_END) - 1);
free(cp);
return buffer_len(blob);
}
static Key *
key_parse_private2(Buffer *blob, int type, const char *passphrase,
char **commentp)
{
u_char *key = NULL, *cp, *salt = NULL, pad, last;
char *comment = NULL, *ciphername = NULL, *kdfname = NULL, *kdfp;
u_int keylen = 0, ivlen, blocksize, slen, klen, len, rounds, nkeys;
u_int check1, check2, m1len, m2len;
size_t authlen;
const Cipher *c;
Buffer b, encoded, copy, kdf;
CipherContext ctx;
Key *k = NULL;
int dlen, ret, i;
buffer_init(&b);
buffer_init(&kdf);
buffer_init(&encoded);
buffer_init(&copy);
/* uudecode */
m1len = sizeof(MARK_BEGIN) - 1;
m2len = sizeof(MARK_END) - 1;
cp = buffer_ptr(blob);
len = buffer_len(blob);
if (len < m1len || memcmp(cp, MARK_BEGIN, m1len)) {
debug("%s: missing begin marker", __func__);
goto out;
}
cp += m1len;
len -= m1len;
while (len) {
if (*cp != '\n' && *cp != '\r')
buffer_put_char(&encoded, *cp);
last = *cp;
len--;
cp++;
if (last == '\n') {
if (len >= m2len && !memcmp(cp, MARK_END, m2len)) {
buffer_put_char(&encoded, '\0');
break;
}
}
}
if (!len) {
debug("%s: no end marker", __func__);
goto out;
}
len = buffer_len(&encoded);
if ((cp = buffer_append_space(&copy, len)) == NULL) {
error("%s: buffer_append_space", __func__);
goto out;
}
if ((dlen = uudecode(buffer_ptr(&encoded), cp, len)) < 0) {
error("%s: uudecode failed", __func__);
goto out;
}
if ((u_int)dlen > len) {
error("%s: crazy uudecode length %d > %u", __func__, dlen, len);
goto out;
}
buffer_consume_end(&copy, len - dlen);
if (buffer_len(&copy) < sizeof(AUTH_MAGIC) ||
memcmp(buffer_ptr(&copy), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
error("%s: bad magic", __func__);
goto out;
}
buffer_consume(&copy, sizeof(AUTH_MAGIC));
ciphername = buffer_get_cstring_ret(&copy, NULL);
if (ciphername == NULL ||
(c = cipher_by_name(ciphername)) == NULL) {
error("%s: unknown cipher name", __func__);
goto out;
}
if ((passphrase == NULL || !strlen(passphrase)) &&
strcmp(ciphername, "none") != 0) {
/* passphrase required */
goto out;
}
kdfname = buffer_get_cstring_ret(&copy, NULL);
if (kdfname == NULL ||
(!strcmp(kdfname, "none") && !strcmp(kdfname, "bcrypt"))) {
error("%s: unknown kdf name", __func__);
goto out;
}
if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) {
error("%s: cipher %s requires kdf", __func__, ciphername);
goto out;
}
/* kdf options */
kdfp = buffer_get_string_ptr_ret(&copy, &klen);
if (kdfp == NULL) {
error("%s: kdf options not set", __func__);
goto out;
}
if (klen > 0) {
if ((cp = buffer_append_space(&kdf, klen)) == NULL) {
error("%s: kdf alloc failed", __func__);
goto out;
}
memcpy(cp, kdfp, klen);
}
/* number of keys */
if (buffer_get_int_ret(&nkeys, &copy) < 0) {
error("%s: key counter missing", __func__);
goto out;
}
if (nkeys != 1) {
error("%s: only one key supported", __func__);
goto out;
}
/* pubkey */
if ((cp = buffer_get_string_ret(&copy, &len)) == NULL) {
error("%s: pubkey not found", __func__);
goto out;
}
free(cp); /* XXX check pubkey against decrypted private key */
/* size of encrypted key blob */
len = buffer_get_int(&copy);
blocksize = cipher_blocksize(c);
authlen = cipher_authlen(c);
if (len < blocksize) {
error("%s: encrypted data too small", __func__);
goto out;
}
if (len % blocksize) {
error("%s: length not multiple of blocksize", __func__);
goto out;
}
/* setup key */
keylen = cipher_keylen(c);
ivlen = cipher_ivlen(c);
key = xcalloc(1, keylen + ivlen);
if (!strcmp(kdfname, "bcrypt")) {
if ((salt = buffer_get_string_ret(&kdf, &slen)) == NULL) {
error("%s: salt not set", __func__);
goto out;
}
if (buffer_get_int_ret(&rounds, &kdf) < 0) {
error("%s: rounds not set", __func__);
goto out;
}
if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
key, keylen + ivlen, rounds) < 0) {
error("%s: bcrypt_pbkdf failed", __func__);
goto out;
}
}
cp = buffer_append_space(&b, len);
cipher_init(&ctx, c, key, keylen, key + keylen, ivlen, 0);
ret = cipher_crypt(&ctx, 0, cp, buffer_ptr(&copy), len, 0, authlen);
cipher_cleanup(&ctx);
buffer_consume(&copy, len);
/* fail silently on decryption errors */
if (ret != 0) {
debug("%s: decrypt failed", __func__);
goto out;
}
if (buffer_len(&copy) != 0) {
error("%s: key blob has trailing data (len = %u)", __func__,
buffer_len(&copy));
goto out;
}
/* check bytes */
if (buffer_get_int_ret(&check1, &b) < 0 ||
buffer_get_int_ret(&check2, &b) < 0) {
error("check bytes missing");
goto out;
}
if (check1 != check2) {
debug("%s: decrypt failed: 0x%08x != 0x%08x", __func__,
check1, check2);
goto out;
}
k = key_private_deserialize(&b);
/* comment */
comment = buffer_get_cstring_ret(&b, NULL);
i = 0;
while (buffer_len(&b)) {
if (buffer_get_char_ret(&pad, &b) == -1 ||
pad != (++i & 0xff)) {
error("%s: bad padding", __func__);
key_free(k);
k = NULL;
goto out;
}
}
if (k && commentp) {
*commentp = comment;
comment = NULL;
}
/* XXX decode pubkey and check against private */
out:
free(ciphername);
free(kdfname);
free(salt);
free(comment);
if (key)
memset(key, 0, keylen + ivlen);
free(key);
buffer_free(&encoded);
buffer_free(&copy);
buffer_free(&kdf);
buffer_free(&b);
return k;
}
/*
* Serialises the authentication (private) key to a blob, encrypting it with
* passphrase. The identification of the blob (lowest 64 bits of n) will
@ -149,8 +488,9 @@ key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase,
cipher_set_key_string(&ciphercontext, cipher, passphrase,
CIPHER_ENCRYPT);
cipher_crypt(&ciphercontext, 0, cp,
buffer_ptr(&buffer), buffer_len(&buffer), 0, 0);
if (cipher_crypt(&ciphercontext, 0, cp,
buffer_ptr(&buffer), buffer_len(&buffer), 0, 0) != 0)
fatal("%s: cipher_crypt failed", __func__);
cipher_cleanup(&ciphercontext);
memset(&ciphercontext, 0, sizeof(ciphercontext));
@ -239,7 +579,8 @@ key_save_private_blob(Buffer *keybuf, const char *filename)
/* Serialise "key" to buffer "blob" */
static int
key_private_to_blob(Key *key, Buffer *blob, const char *passphrase,
const char *comment)
const char *comment, int force_new_format, const char *new_format_cipher,
int new_format_rounds)
{
switch (key->type) {
case KEY_RSA1:
@ -247,6 +588,10 @@ key_private_to_blob(Key *key, Buffer *blob, const char *passphrase,
case KEY_DSA:
case KEY_ECDSA:
case KEY_RSA:
if (force_new_format) {
return key_private_to_blob2(key, blob, passphrase,
comment, new_format_cipher, new_format_rounds);
}
return key_private_pem_to_blob(key, blob, passphrase, comment);
default:
error("%s: cannot save key type %d", __func__, key->type);
@ -256,13 +601,15 @@ key_private_to_blob(Key *key, Buffer *blob, const char *passphrase,
int
key_save_private(Key *key, const char *filename, const char *passphrase,
const char *comment)
const char *comment, int force_new_format, const char *new_format_cipher,
int new_format_rounds)
{
Buffer keyblob;
int success = 0;
buffer_init(&keyblob);
if (!key_private_to_blob(key, &keyblob, passphrase, comment))
if (!key_private_to_blob(key, &keyblob, passphrase, comment,
force_new_format, new_format_cipher, new_format_rounds))
goto out;
if (!key_save_private_blob(&keyblob, filename))
goto out;
@ -473,8 +820,9 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
cipher_set_key_string(&ciphercontext, cipher, passphrase,
CIPHER_DECRYPT);
cipher_crypt(&ciphercontext, 0, cp,
buffer_ptr(&copy), buffer_len(&copy), 0, 0);
if (cipher_crypt(&ciphercontext, 0, cp,
buffer_ptr(&copy), buffer_len(&copy), 0, 0) != 0)
fatal("%s: cipher_crypt failed", __func__);
cipher_cleanup(&ciphercontext);
memset(&ciphercontext, 0, sizeof(ciphercontext));
buffer_free(&copy);
@ -641,6 +989,8 @@ static Key *
key_parse_private_type(Buffer *blob, int type, const char *passphrase,
char **commentp)
{
Key *k;
switch (type) {
case KEY_RSA1:
return key_parse_private_rsa1(blob, passphrase, commentp);
@ -648,6 +998,8 @@ key_parse_private_type(Buffer *blob, int type, const char *passphrase,
case KEY_ECDSA:
case KEY_RSA:
case KEY_UNSPEC:
if ((k = key_parse_private2(blob, type, passphrase, commentp)))
return k;
return key_parse_private_pem(blob, type, passphrase, commentp);
default:
error("%s: cannot parse key type %d", __func__, type);
@ -943,4 +1295,3 @@ key_in_file(Key *key, const char *filename, int strict_type)
fclose(f);
return ret;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfile.h,v 1.16 2011/05/04 21:15:29 djm Exp $ */
/* $OpenBSD: authfile.h,v 1.17 2013/12/06 13:34:54 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -15,7 +15,8 @@
#ifndef AUTHFILE_H
#define AUTHFILE_H
int key_save_private(Key *, const char *, const char *, const char *);
int key_save_private(Key *, const char *, const char *, const char *,
int, const char *, int);
int key_load_file(int, const char *, Buffer *);
Key *key_load_cert(const char *);
Key *key_load_public(const char *, char **);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: cipher.c,v 1.92 2013/12/02 03:13:14 djm Exp $ */
/* $OpenBSD: cipher.c,v 1.93 2013/12/06 13:34:54 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -344,17 +344,16 @@ cipher_init(CipherContext *cc, const Cipher *cipher,
* Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag.
* This tag is written on encryption and verified on decryption.
* Both 'aadlen' and 'authlen' can be set to 0.
* cipher_crypt() returns 0 on success and -1 if the decryption integrity
* check fails.
*/
void
int
cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src,
u_int len, u_int aadlen, u_int authlen)
{
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
if (chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen,
authlen, cc->encrypt) != 0)
fatal("Decryption integrity check failed");
return;
}
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, len,
aadlen, authlen, cc->encrypt);
if (authlen) {
u_char lastiv[1];
@ -387,13 +386,14 @@ cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src,
if (cc->encrypt)
fatal("%s: EVP_Cipher(final) failed", __func__);
else
fatal("Decryption integrity check failed");
return -1;
}
if (cc->encrypt &&
!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG,
authlen, dest + aadlen + len))
fatal("%s: EVP_CTRL_GCM_GET_TAG", __func__);
}
return 0;
}
/* Extract the packet length, including any decryption necessary beforehand */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: cipher.h,v 1.42 2013/11/21 00:45:44 djm Exp $ */
/* $OpenBSD: cipher.h,v 1.43 2013/12/06 13:34:54 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -81,7 +81,7 @@ int ciphers_valid(const char *);
char *cipher_alg_list(char, int);
void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int,
const u_char *, u_int, int);
void cipher_crypt(CipherContext *, u_int, u_char *, const u_char *,
int cipher_crypt(CipherContext *, u_int, u_char *, const u_char *,
u_int, u_int, u_int);
int cipher_get_length(CipherContext *, u_int *, u_int,
const u_char *, u_int);

3
key.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: key.c,v 1.107 2013/12/06 13:30:08 markus Exp $ */
/* $OpenBSD: key.c,v 1.108 2013/12/06 13:34:54 markus Exp $ */
/*
* read_bignum():
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1892,6 +1892,7 @@ key_certify(Key *k, Key *ca)
if (!key_cert_is_legacy(k))
buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce));
/* XXX this substantially duplicates to_blob(); refactor */
switch (k->type) {
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT:

View File

@ -1,4 +1,4 @@
/* $OpenBSD: packet.c,v 1.190 2013/11/21 00:45:44 djm Exp $ */
/* $OpenBSD: packet.c,v 1.191 2013/12/06 13:34:54 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -713,9 +713,10 @@ packet_send1(void)
buffer_append(&active_state->output, buf, 4);
cp = buffer_append_space(&active_state->output,
buffer_len(&active_state->outgoing_packet));
cipher_crypt(&active_state->send_context, 0, cp,
if (cipher_crypt(&active_state->send_context, 0, cp,
buffer_ptr(&active_state->outgoing_packet),
buffer_len(&active_state->outgoing_packet), 0, 0);
buffer_len(&active_state->outgoing_packet), 0, 0) != 0)
fatal("%s: cipher_crypt failed", __func__);
#ifdef PACKET_DEBUG
fprintf(stderr, "encrypted: ");
@ -946,9 +947,10 @@ packet_send2_wrapped(void)
}
/* encrypt packet and append to output buffer. */
cp = buffer_append_space(&active_state->output, len + authlen);
cipher_crypt(&active_state->send_context, active_state->p_send.seqnr,
if (cipher_crypt(&active_state->send_context, active_state->p_send.seqnr,
cp, buffer_ptr(&active_state->outgoing_packet),
len - aadlen, aadlen, authlen);
len - aadlen, aadlen, authlen) != 0)
fatal("%s: cipher_crypt failed", __func__);
/* append unencrypted MAC */
if (mac && mac->enabled) {
if (mac->etm) {
@ -1208,8 +1210,9 @@ packet_read_poll1(void)
/* Decrypt data to incoming_packet. */
buffer_clear(&active_state->incoming_packet);
cp = buffer_append_space(&active_state->incoming_packet, padded_len);
cipher_crypt(&active_state->receive_context, 0, cp,
buffer_ptr(&active_state->input), padded_len, 0, 0);
if (cipher_crypt(&active_state->receive_context, 0, cp,
buffer_ptr(&active_state->input), padded_len, 0, 0) != 0)
fatal("%s: cipher_crypt failed", __func__);
buffer_consume(&active_state->input, padded_len);
@ -1304,9 +1307,10 @@ packet_read_poll2(u_int32_t *seqnr_p)
buffer_clear(&active_state->incoming_packet);
cp = buffer_append_space(&active_state->incoming_packet,
block_size);
cipher_crypt(&active_state->receive_context,
if (cipher_crypt(&active_state->receive_context,
active_state->p_read.seqnr, cp,
buffer_ptr(&active_state->input), block_size, 0, 0);
buffer_ptr(&active_state->input), block_size, 0, 0) != 0)
fatal("Decryption integrity check failed");
cp = buffer_ptr(&active_state->incoming_packet);
active_state->packlen = get_u32(cp);
if (active_state->packlen < 1 + 4 ||
@ -1360,9 +1364,10 @@ packet_read_poll2(u_int32_t *seqnr_p)
macbuf = mac_compute(mac, active_state->p_read.seqnr,
buffer_ptr(&active_state->input), aadlen + need);
cp = buffer_append_space(&active_state->incoming_packet, aadlen + need);
cipher_crypt(&active_state->receive_context,
if (cipher_crypt(&active_state->receive_context,
active_state->p_read.seqnr, cp,
buffer_ptr(&active_state->input), need, aadlen, authlen);
buffer_ptr(&active_state->input), need, aadlen, authlen) != 0)
fatal("Decryption integrity check failed");
buffer_consume(&active_state->input, aadlen + need + authlen);
/*
* compute MAC over seqnr and packet,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-agent.c,v 1.178 2013/12/06 13:30:08 markus Exp $ */
/* $OpenBSD: ssh-agent.c,v 1.179 2013/12/06 13:34:54 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -484,7 +484,6 @@ process_add_identity(SocketEntry *e, int version)
/* Generate additional parameters */
rsa_generate_additional_parameters(k->rsa);
/* enable blinding */
if (RSA_blinding_on(k->rsa, NULL) != 1) {
error("process_add_identity: RSA_blinding_on failed");
key_free(k);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keygen.c,v 1.236 2013/12/06 03:40:51 djm Exp $ */
/* $OpenBSD: ssh-keygen.c,v 1.237 2013/12/06 13:34:54 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -150,6 +150,18 @@ char *key_type_name = NULL;
/* Load key from this PKCS#11 provider */
char *pkcs11provider = NULL;
/* Use new OpenSSH private key format when writing SSH2 keys instead of PEM */
int use_new_format = 0;
/* Cipher for new-format private keys */
char *new_format_cipher = NULL;
/*
* Number of KDF rounds to derive new format keys /
* number of primality trials when screening moduli.
*/
int rounds = 0;
/* argv0 */
extern char *__progname;
@ -923,7 +935,8 @@ do_gen_all_hostkeys(struct passwd *pw)
public = key_from_private(private);
snprintf(comment, sizeof comment, "%s@%s", pw->pw_name,
hostname);
if (!key_save_private(private, identity_file, "", comment)) {
if (!key_save_private(private, identity_file, "", comment,
use_new_format, new_format_cipher, rounds)) {
printf("Saving the key failed: %s.\n", identity_file);
key_free(private);
key_free(public);
@ -1275,7 +1288,8 @@ do_change_passphrase(struct passwd *pw)
}
/* Save the file using the new passphrase. */
if (!key_save_private(private, identity_file, passphrase1, comment)) {
if (!key_save_private(private, identity_file, passphrase1, comment,
use_new_format, new_format_cipher, rounds)) {
printf("Saving the key failed: %s.\n", identity_file);
memset(passphrase1, 0, strlen(passphrase1));
free(passphrase1);
@ -1385,7 +1399,8 @@ do_change_comment(struct passwd *pw)
}
/* Save the file using the new passphrase. */
if (!key_save_private(private, identity_file, passphrase, new_comment)) {
if (!key_save_private(private, identity_file, passphrase, new_comment,
use_new_format, new_format_cipher, rounds)) {
printf("Saving the key failed: %s.\n", identity_file);
memset(passphrase, 0, strlen(passphrase));
free(passphrase);
@ -2132,7 +2147,7 @@ usage(void)
fprintf(stderr, "usage: %s [options]\n", __progname);
fprintf(stderr, "Options:\n");
fprintf(stderr, " -A Generate non-existent host keys for all key types.\n");
fprintf(stderr, " -a trials Number of trials for screening DH-GEX moduli.\n");
fprintf(stderr, " -a number Number of KDF rounds for new key format or moduli primality tests.\n");
fprintf(stderr, " -B Show bubblebabble digest of key file.\n");
fprintf(stderr, " -b bits Number of bits in the key to create.\n");
fprintf(stderr, " -C comment Provide new comment.\n");
@ -2160,6 +2175,7 @@ usage(void)
fprintf(stderr, " -N phrase Provide new passphrase.\n");
fprintf(stderr, " -n name,... User/host principal names to include in certificate\n");
fprintf(stderr, " -O option Specify a certificate option.\n");
fprintf(stderr, " -o Enforce new private key format.\n");
fprintf(stderr, " -P phrase Provide old passphrase.\n");
fprintf(stderr, " -p Change passphrase of private key file.\n");
fprintf(stderr, " -Q Test whether key(s) are revoked in KRL.\n");
@ -2176,6 +2192,7 @@ usage(void)
fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n");
fprintf(stderr, " -y Read private key file and print public key.\n");
fprintf(stderr, " -z serial Specify a serial number.\n");
fprintf(stderr, " -Z cipher Specify a cipher for new private key format.\n");
exit(1);
}
@ -2193,7 +2210,7 @@ main(int argc, char **argv)
struct passwd *pw;
struct stat st;
int opt, type, fd;
u_int32_t memory = 0, generator_wanted = 0, trials = 100;
u_int32_t memory = 0, generator_wanted = 0;
int do_gen_candidates = 0, do_screen_candidates = 0;
int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0;
unsigned long start_lineno = 0, lines_to_process = 0;
@ -2225,9 +2242,9 @@ main(int argc, char **argv)
exit(1);
}
/* Remaining characters: EUYZdow */
while ((opt = getopt(argc, argv, "ABHLQXceghiklpquvxy"
"C:D:F:G:I:J:K:M:N:O:P:R:S:T:V:W:a:b:f:j:m:n:r:s:t:z:")) != -1) {
/* Remaining characters: EUYdw */
while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy"
"C:D:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:a:b:f:g:j:m:n:r:s:t:z:")) != -1) {
switch (opt) {
case 'A':
gen_all_hostkeys = 1;
@ -2285,6 +2302,9 @@ main(int argc, char **argv)
case 'n':
cert_principals = optarg;
break;
case 'o':
use_new_format = 1;
break;
case 'p':
change_passphrase = 1;
break;
@ -2312,6 +2332,9 @@ main(int argc, char **argv)
case 'O':
add_cert_option(optarg);
break;
case 'Z':
new_format_cipher = optarg;
break;
case 'C':
identity_comment = optarg;
break;
@ -2370,9 +2393,9 @@ main(int argc, char **argv)
optarg, errstr);
break;
case 'a':
trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
rounds = (int)strtonum(optarg, 1, INT_MAX, &errstr);
if (errstr)
fatal("Invalid number of trials: %s (%s)",
fatal("Invalid number: %s (%s)",
optarg, errstr);
break;
case 'M':
@ -2531,7 +2554,8 @@ main(int argc, char **argv)
fatal("Couldn't open moduli file \"%s\": %s",
out_file, strerror(errno));
}
if (prime_test(in, out, trials, generator_wanted, checkpoint,
if (prime_test(in, out, rounds == 0 ? 100 : rounds,
generator_wanted, checkpoint,
start_lineno, lines_to_process) != 0)
fatal("modulus screening failed");
return (0);
@ -2623,7 +2647,8 @@ passphrase_again:
}
/* Save the key with the given passphrase and comment. */
if (!key_save_private(private, identity_file, passphrase1, comment)) {
if (!key_save_private(private, identity_file, passphrase1, comment,
use_new_format, new_format_cipher, rounds)) {
printf("Saving the key failed: %s.\n", identity_file);
memset(passphrase1, 0, strlen(passphrase1));
free(passphrase1);