- djm@cvs.openbsd.org 2010/04/16 01:47:26

[PROTOCOL.certkeys auth-options.c auth-options.h auth-rsa.c]
     [auth2-pubkey.c authfd.c key.c key.h myproposal.h ssh-add.c]
     [ssh-agent.c ssh-dss.c ssh-keygen.1 ssh-keygen.c ssh-rsa.c]
     [sshconnect.c sshconnect2.c sshd.c]
     revised certificate format ssh-{dss,rsa}-cert-v01@openssh.com with the
     following changes:

     move the nonce field to the beginning of the certificate where it can
     better protect against chosen-prefix attacks on the signature hash

     Rename "constraints" field to "critical options"

     Add a new non-critical "extensions" field

     Add a serial number

     The older format is still support for authentication and cert generation
     (use "ssh-keygen -t v00 -s ca_key ..." to generate a v00 certificate)

     ok markus@
This commit is contained in:
Damien Miller 2010-04-16 15:56:21 +10:00
parent 031c9100df
commit 4e270b05dd
19 changed files with 449 additions and 213 deletions

View File

@ -41,6 +41,27 @@
retry lookup for private key if there's no matching key with CKA_SIGN retry lookup for private key if there's no matching key with CKA_SIGN
attribute enabled; this fixes fixes MuscleCard support (bugzilla #1736) attribute enabled; this fixes fixes MuscleCard support (bugzilla #1736)
ok djm@ ok djm@
- djm@cvs.openbsd.org 2010/04/16 01:47:26
[PROTOCOL.certkeys auth-options.c auth-options.h auth-rsa.c]
[auth2-pubkey.c authfd.c key.c key.h myproposal.h ssh-add.c]
[ssh-agent.c ssh-dss.c ssh-keygen.1 ssh-keygen.c ssh-rsa.c]
[sshconnect.c sshconnect2.c sshd.c]
revised certificate format ssh-{dss,rsa}-cert-v01@openssh.com with the
following changes:
move the nonce field to the beginning of the certificate where it can
better protect against chosen-prefix attacks on the signature hash
Rename "constraints" field to "critical options"
Add a new non-critical "extensions" field
Add a serial number
The older format is still support for authentication and cert generation
(use "ssh-keygen -t v00 -s ca_key ..." to generate a v00 certificate)
ok markus@
20100410 20100410
- (dtucker) [configure.ac] Put the check for the existence of getaddrinfo - (dtucker) [configure.ac] Put the check for the existence of getaddrinfo

View File

@ -16,7 +16,7 @@ These protocol extensions build on the simple public key authentication
system already in SSH to allow certificate-based authentication. system already in SSH to allow certificate-based authentication.
The certificates used are not traditional X.509 certificates, with The certificates used are not traditional X.509 certificates, with
numerous options and complex encoding rules, but something rather numerous options and complex encoding rules, but something rather
more minimal: a key, some identity information and usage constraints more minimal: a key, some identity information and usage options
that have been signed with some other trusted key. that have been signed with some other trusted key.
A sshd server may be configured to allow authentication via certified A sshd server may be configured to allow authentication via certified
@ -27,7 +27,7 @@ of acceptance of certified host keys, by adding a similar ability
to specify CA keys in ~/.ssh/known_hosts. to specify CA keys in ~/.ssh/known_hosts.
Certified keys are represented using two new key types: Certified keys are represented using two new key types:
ssh-rsa-cert-v00@openssh.com and ssh-dss-cert-v00@openssh.com that ssh-rsa-cert-v01@openssh.com and ssh-dss-cert-v01@openssh.com that
include certification information along with the public key that is used include certification information along with the public key that is used
to sign challenges. ssh-keygen performs the CA signing operation. to sign challenges. ssh-keygen performs the CA signing operation.
@ -47,7 +47,7 @@ in RFC4252 section 7.
New public key formats New public key formats
---------------------- ----------------------
The ssh-rsa-cert-v00@openssh.com and ssh-dss-cert-v00@openssh.com key The ssh-rsa-cert-v01@openssh.com and ssh-dss-cert-v01@openssh.com key
types take a similar high-level format (note: data types and types take a similar high-level format (note: data types and
encoding are as per RFC4251 section 5). The serialised wire encoding of encoding are as per RFC4251 section 5). The serialised wire encoding of
these certificates is also used for storing them on disk. these certificates is also used for storing them on disk.
@ -57,42 +57,55 @@ these certificates is also used for storing them on disk.
RSA certificate RSA certificate
string "ssh-rsa-cert-v00@openssh.com" string "ssh-rsa-cert-v01@openssh.com"
string nonce
mpint e mpint e
mpint n mpint n
uint64 serial
uint32 type uint32 type
string key id string key id
string valid principals string valid principals
uint64 valid after uint64 valid after
uint64 valid before uint64 valid before
string constraints string critical options
string nonce string extensions
string reserved string reserved
string signature key string signature key
string signature string signature
DSA certificate DSA certificate
string "ssh-dss-cert-v00@openssh.com" string "ssh-dss-cert-v01@openssh.com"
string nonce
mpint p mpint p
mpint q mpint q
mpint g mpint g
mpint y mpint y
uint64 serial
uint32 type uint32 type
string key id string key id
string valid principals string valid principals
uint64 valid after uint64 valid after
uint64 valid before uint64 valid before
string constraints string critical options
string nonce string extensions
string reserved string reserved
string signature key string signature key
string signature string signature
The nonce field is a CA-provided random bitstring of arbitrary length
(but typically 16 or 32 bytes) included to make attacks that depend on
inducing collisions in the signature hash infeasible.
e and n are the RSA exponent and public modulus respectively. e and n are the RSA exponent and public modulus respectively.
p, q, g, y are the DSA parameters as described in FIPS-186-2. p, q, g, y are the DSA parameters as described in FIPS-186-2.
serial is an optional certificate serial number set by the CA to
provide an abbreviated way to refer to certificates from that CA.
If a CA does not with to number its certificates it must set this
field to zero.
type specifies whether this certificate is for identification of a user type specifies whether this certificate is for identification of a user
or a host using a SSH_CERT_TYPE_... value. or a host using a SSH_CERT_TYPE_... value.
@ -112,13 +125,15 @@ certificate. Each represents a time in seconds since 1970-01-01
00:00:00. A certificate is considered valid if: 00:00:00. A certificate is considered valid if:
valid after <= current time < valid before valid after <= current time < valid before
constraints is a set of zero or more key constraints encoded as below. criticial options is a set of zero or more key options encoded as
below. All such options are "critical" in the sense that an implementation
must refuse to authorise a key that has an unrecognised option.
The nonce field is a CA-provided random bitstring of arbitrary length extensions is a set of zero or more optional extensions. These extensions
(but typically 16 or 32 bytes) included to make attacks that depend on are not critical, and an implementation that encounters one that it does
inducing collisions in the signature hash infeasible. not recognise may safely ignore it. No extensions are defined at present.
The reserved field is current unused and is ignored in this version of The reserved field is currently unused and is ignored in this version of
the protocol. the protocol.
signature key contains the CA key used to sign the certificate. signature key contains the CA key used to sign the certificate.
@ -132,22 +147,22 @@ up to, and including the signature key. Signatures are computed and
encoded according to the rules defined for the CA's public key algorithm encoded according to the rules defined for the CA's public key algorithm
(RFC4253 section 6.6 for ssh-rsa and ssh-dss). (RFC4253 section 6.6 for ssh-rsa and ssh-dss).
Constraints Critical options
----------- ----------------
The constraints section of the certificate specifies zero or more The critical options section of the certificate specifies zero or more
constraints on the certificates validity. The format of this field options on the certificates validity. The format of this field
is a sequence of zero or more tuples: is a sequence of zero or more tuples:
string name string name
string data string data
The name field identifies the constraint and the data field encodes The name field identifies the option and the data field encodes
constraint-specific information (see below). All constraints are option-specific information (see below). All options are
"critical", if an implementation does not recognise a constraint "critical", if an implementation does not recognise a option
then the validating party should refuse to accept the certificate. then the validating party should refuse to accept the certificate.
The supported constraints and the contents and structure of their The supported options and the contents and structure of their
data fields are: data fields are:
Name Format Description Name Format Description
@ -159,35 +174,35 @@ force-command string Specifies a command that is executed
permit-X11-forwarding empty Flag indicating that X11 forwarding permit-X11-forwarding empty Flag indicating that X11 forwarding
should be permitted. X11 forwarding will should be permitted. X11 forwarding will
be refused if this constraint is absent. be refused if this option is absent.
permit-agent-forwarding empty Flag indicating that agent forwarding permit-agent-forwarding empty Flag indicating that agent forwarding
should be allowed. Agent forwarding should be allowed. Agent forwarding
must not be permitted unless this must not be permitted unless this
constraint is present. option is present.
permit-port-forwarding empty Flag indicating that port-forwarding permit-port-forwarding empty Flag indicating that port-forwarding
should be allowed. If this constraint is should be allowed. If this option is
not present then no port forwarding will not present then no port forwarding will
be allowed. be allowed.
permit-pty empty Flag indicating that PTY allocation permit-pty empty Flag indicating that PTY allocation
should be permitted. In the absence of should be permitted. In the absence of
this constraint PTY allocation will be this option PTY allocation will be
disabled. disabled.
permit-user-rc empty Flag indicating that execution of permit-user-rc empty Flag indicating that execution of
~/.ssh/rc should be permitted. Execution ~/.ssh/rc should be permitted. Execution
of this script will not be permitted if of this script will not be permitted if
this constraint is not present. this option is not present.
source-address string Comma-separated list of source addresses source-address string Comma-separated list of source addresses
from which this certificate is accepted from which this certificate is accepted
for authentication. Addresses are for authentication. Addresses are
specified in CIDR format (nn.nn.nn.nn/nn specified in CIDR format (nn.nn.nn.nn/nn
or hhhh::hhhh/nn). or hhhh::hhhh/nn).
If this constraint is not present then If this option is not present then
certificates may be presented from any certificates may be presented from any
source address. source address.
$OpenBSD: PROTOCOL.certkeys,v 1.3 2010/03/03 22:50:40 djm Exp $ $OpenBSD: PROTOCOL.certkeys,v 1.4 2010/04/16 01:47:25 djm Exp $

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth-options.c,v 1.49 2010/03/16 15:46:52 stevesk Exp $ */ /* $OpenBSD: auth-options.c,v 1.50 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -27,10 +27,10 @@
#include "canohost.h" #include "canohost.h"
#include "buffer.h" #include "buffer.h"
#include "channels.h" #include "channels.h"
#include "auth-options.h"
#include "servconf.h" #include "servconf.h"
#include "misc.h" #include "misc.h"
#include "key.h" #include "key.h"
#include "auth-options.h"
#include "hostfile.h" #include "hostfile.h"
#include "auth.h" #include "auth.h"
#ifdef GSSAPI #ifdef GSSAPI
@ -377,11 +377,11 @@ bad_option:
} }
/* /*
* Set options from certificate constraints. These supersede user key options * Set options from critical certificate options. These supersede user key
* so this must be called after auth_parse_options(). * options so this must be called after auth_parse_options().
*/ */
int int
auth_cert_constraints(Buffer *c_orig, struct passwd *pw) auth_cert_options(Key *k, struct passwd *pw)
{ {
u_char *name = NULL, *data_blob = NULL; u_char *name = NULL, *data_blob = NULL;
u_int nlen, dlen, clen; u_int nlen, dlen, clen;
@ -400,12 +400,13 @@ auth_cert_constraints(Buffer *c_orig, struct passwd *pw)
/* Make copy to avoid altering original */ /* Make copy to avoid altering original */
buffer_init(&c); buffer_init(&c);
buffer_append(&c, buffer_ptr(c_orig), buffer_len(c_orig)); buffer_append(&c,
buffer_ptr(&k->cert->critical), buffer_len(&k->cert->critical));
while (buffer_len(&c) > 0) { while (buffer_len(&c) > 0) {
if ((name = buffer_get_string_ret(&c, &nlen)) == NULL || if ((name = buffer_get_string_ret(&c, &nlen)) == NULL ||
(data_blob = buffer_get_string_ret(&c, &dlen)) == NULL) { (data_blob = buffer_get_string_ret(&c, &dlen)) == NULL) {
error("Certificate constraints corrupt"); error("Certificate options corrupt");
goto out; goto out;
} }
buffer_append(&data, data_blob, dlen); buffer_append(&data, data_blob, dlen);
@ -439,7 +440,7 @@ auth_cert_constraints(Buffer *c_orig, struct passwd *pw)
} }
if (cert_forced_command != NULL) { if (cert_forced_command != NULL) {
error("Certificate has multiple " error("Certificate has multiple "
"force-command constraints"); "force-command options");
xfree(command); xfree(command);
goto out; goto out;
} }
@ -459,7 +460,7 @@ auth_cert_constraints(Buffer *c_orig, struct passwd *pw)
} }
if (cert_source_address_done++) { if (cert_source_address_done++) {
error("Certificate has multiple " error("Certificate has multiple "
"source-address constraints"); "source-address options");
xfree(allowed); xfree(allowed);
goto out; goto out;
} }
@ -502,7 +503,7 @@ auth_cert_constraints(Buffer *c_orig, struct passwd *pw)
name = data_blob = NULL; name = data_blob = NULL;
} }
/* successfully parsed all constraints */ /* successfully parsed all options */
ret = 0; ret = 0;
no_port_forwarding_flag |= cert_no_port_forwarding_flag; no_port_forwarding_flag |= cert_no_port_forwarding_flag;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth-options.h,v 1.18 2010/02/26 20:29:54 djm Exp $ */ /* $OpenBSD: auth-options.h,v 1.19 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -34,6 +34,6 @@ extern int key_is_cert_authority;
int auth_parse_options(struct passwd *, char *, char *, u_long); int auth_parse_options(struct passwd *, char *, char *, u_long);
void auth_clear_options(void); void auth_clear_options(void);
int auth_cert_constraints(Buffer *, struct passwd *); int auth_cert_options(Key *, struct passwd *);
#endif #endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth-rsa.c,v 1.74 2010/03/04 10:36:03 djm Exp $ */ /* $OpenBSD: auth-rsa.c,v 1.75 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -34,11 +34,11 @@
#include "uidswap.h" #include "uidswap.h"
#include "match.h" #include "match.h"
#include "buffer.h" #include "buffer.h"
#include "auth-options.h"
#include "pathnames.h" #include "pathnames.h"
#include "log.h" #include "log.h"
#include "servconf.h" #include "servconf.h"
#include "key.h" #include "key.h"
#include "auth-options.h"
#include "hostfile.h" #include "hostfile.h"
#include "auth.h" #include "auth.h"
#ifdef GSSAPI #ifdef GSSAPI

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-pubkey.c,v 1.22 2010/03/10 23:27:17 djm Exp $ */ /* $OpenBSD: auth2-pubkey.c,v 1.23 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -235,7 +235,7 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
} }
if (auth_parse_options(pw, key_options, file, linenum) != 1) if (auth_parse_options(pw, key_options, file, linenum) != 1)
continue; continue;
if (key->type == KEY_RSA_CERT || key->type == KEY_DSA_CERT) { if (key_is_cert(key)) {
if (!key_is_cert_authority) if (!key_is_cert_authority)
continue; continue;
if (!key_equal(found, key->cert->signature_key)) if (!key_equal(found, key->cert->signature_key))
@ -251,8 +251,7 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
auth_debug_add("%s", reason); auth_debug_add("%s", reason);
continue; continue;
} }
if (auth_cert_constraints(&key->cert->constraints, if (auth_cert_options(key, pw) != 0) {
pw) != 0) {
xfree(fp); xfree(fp);
continue; continue;
} }
@ -307,7 +306,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
auth_debug_add("%s", reason); auth_debug_add("%s", reason);
goto out; goto out;
} }
if (auth_cert_constraints(&key->cert->constraints, pw) != 0) if (auth_cert_options(key, pw) != 0)
goto out; goto out;
verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s", verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s",

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfd.c,v 1.82 2010/02/26 20:29:54 djm Exp $ */ /* $OpenBSD: authfd.c,v 1.83 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -483,6 +483,7 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
buffer_put_bignum2(b, key->rsa->p); buffer_put_bignum2(b, key->rsa->p);
buffer_put_bignum2(b, key->rsa->q); buffer_put_bignum2(b, key->rsa->q);
break; break;
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0) if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
fatal("%s: no cert/certblob", __func__); fatal("%s: no cert/certblob", __func__);
@ -500,6 +501,7 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
buffer_put_bignum2(b, key->dsa->pub_key); buffer_put_bignum2(b, key->dsa->pub_key);
buffer_put_bignum2(b, key->dsa->priv_key); buffer_put_bignum2(b, key->dsa->priv_key);
break; break;
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0) if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
fatal("%s: no cert/certblob", __func__); fatal("%s: no cert/certblob", __func__);
@ -535,8 +537,10 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key,
break; break;
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT: case KEY_RSA_CERT:
case KEY_RSA_CERT_V00:
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT: case KEY_DSA_CERT:
case KEY_DSA_CERT_V00:
type = constrained ? type = constrained ?
SSH2_AGENTC_ADD_ID_CONSTRAINED : SSH2_AGENTC_ADD_ID_CONSTRAINED :
SSH2_AGENTC_ADD_IDENTITY; SSH2_AGENTC_ADD_IDENTITY;

177
key.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: key.c,v 1.86 2010/03/15 19:40:02 stevesk Exp $ */ /* $OpenBSD: key.c,v 1.87 2010/04/16 01:47:26 djm Exp $ */
/* /*
* read_bignum(): * read_bignum():
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -61,7 +61,8 @@ cert_new(void)
cert = xcalloc(1, sizeof(*cert)); cert = xcalloc(1, sizeof(*cert));
buffer_init(&cert->certblob); buffer_init(&cert->certblob);
buffer_init(&cert->constraints); buffer_init(&cert->critical);
buffer_init(&cert->extensions);
cert->key_id = NULL; cert->key_id = NULL;
cert->principals = NULL; cert->principals = NULL;
cert->signature_key = NULL; cert->signature_key = NULL;
@ -82,6 +83,7 @@ key_new(int type)
switch (k->type) { switch (k->type) {
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
if ((rsa = RSA_new()) == NULL) if ((rsa = RSA_new()) == NULL)
fatal("key_new: RSA_new failed"); fatal("key_new: RSA_new failed");
@ -92,6 +94,7 @@ key_new(int type)
k->rsa = rsa; k->rsa = rsa;
break; break;
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
if ((dsa = DSA_new()) == NULL) if ((dsa = DSA_new()) == NULL)
fatal("key_new: DSA_new failed"); fatal("key_new: DSA_new failed");
@ -124,6 +127,7 @@ key_add_private(Key *k)
switch (k->type) { switch (k->type) {
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
if ((k->rsa->d = BN_new()) == NULL) if ((k->rsa->d = BN_new()) == NULL)
fatal("key_new_private: BN_new failed"); fatal("key_new_private: BN_new failed");
@ -139,6 +143,7 @@ key_add_private(Key *k)
fatal("key_new_private: BN_new failed"); fatal("key_new_private: BN_new failed");
break; break;
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
if ((k->dsa->priv_key = BN_new()) == NULL) if ((k->dsa->priv_key = BN_new()) == NULL)
fatal("key_new_private: BN_new failed"); fatal("key_new_private: BN_new failed");
@ -165,7 +170,8 @@ cert_free(struct KeyCert *cert)
u_int i; u_int i;
buffer_free(&cert->certblob); buffer_free(&cert->certblob);
buffer_free(&cert->constraints); buffer_free(&cert->critical);
buffer_free(&cert->extensions);
if (cert->key_id != NULL) if (cert->key_id != NULL)
xfree(cert->key_id); xfree(cert->key_id);
for (i = 0; i < cert->nprincipals; i++) for (i = 0; i < cert->nprincipals; i++)
@ -184,12 +190,14 @@ key_free(Key *k)
switch (k->type) { switch (k->type) {
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
if (k->rsa != NULL) if (k->rsa != NULL)
RSA_free(k->rsa); RSA_free(k->rsa);
k->rsa = NULL; k->rsa = NULL;
break; break;
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
if (k->dsa != NULL) if (k->dsa != NULL)
DSA_free(k->dsa); DSA_free(k->dsa);
@ -238,11 +246,13 @@ key_equal_public(const Key *a, const Key *b)
switch (a->type) { switch (a->type) {
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
case KEY_RSA: case KEY_RSA:
return a->rsa != NULL && b->rsa != NULL && return a->rsa != NULL && b->rsa != NULL &&
BN_cmp(a->rsa->e, b->rsa->e) == 0 && BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
BN_cmp(a->rsa->n, b->rsa->n) == 0; BN_cmp(a->rsa->n, b->rsa->n) == 0;
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
case KEY_DSA: case KEY_DSA:
return a->dsa != NULL && b->dsa != NULL && return a->dsa != NULL && b->dsa != NULL &&
@ -304,6 +314,8 @@ key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length)
case KEY_RSA: case KEY_RSA:
key_to_blob(k, &blob, &len); key_to_blob(k, &blob, &len);
break; break;
case KEY_DSA_CERT_V00:
case KEY_RSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
case KEY_RSA_CERT: case KEY_RSA_CERT:
/* We want a fingerprint of the _key_ not of the cert */ /* We want a fingerprint of the _key_ not of the cert */
@ -631,6 +643,8 @@ key_read(Key *ret, char **cpp)
case KEY_UNSPEC: case KEY_UNSPEC:
case KEY_RSA: case KEY_RSA:
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT_V00:
case KEY_RSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
case KEY_RSA_CERT: case KEY_RSA_CERT:
space = strchr(cp, ' '); space = strchr(cp, ' ');
@ -757,11 +771,13 @@ key_write(const Key *key, FILE *f)
error("key_write: failed for RSA key"); error("key_write: failed for RSA key");
return 0; return 0;
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
if (key->dsa == NULL) if (key->dsa == NULL)
return 0; return 0;
break; break;
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
if (key->rsa == NULL) if (key->rsa == NULL)
return 0; return 0;
@ -793,6 +809,10 @@ key_type(const Key *k)
return "RSA"; return "RSA";
case KEY_DSA: case KEY_DSA:
return "DSA"; return "DSA";
case KEY_RSA_CERT_V00:
return "RSA-CERT-V00";
case KEY_DSA_CERT_V00:
return "DSA-CERT-V00";
case KEY_RSA_CERT: case KEY_RSA_CERT:
return "RSA-CERT"; return "RSA-CERT";
case KEY_DSA_CERT: case KEY_DSA_CERT:
@ -822,10 +842,14 @@ key_ssh_name(const Key *k)
return "ssh-rsa"; return "ssh-rsa";
case KEY_DSA: case KEY_DSA:
return "ssh-dss"; return "ssh-dss";
case KEY_RSA_CERT: case KEY_RSA_CERT_V00:
return "ssh-rsa-cert-v00@openssh.com"; return "ssh-rsa-cert-v00@openssh.com";
case KEY_DSA_CERT: case KEY_DSA_CERT_V00:
return "ssh-dss-cert-v00@openssh.com"; return "ssh-dss-cert-v00@openssh.com";
case KEY_RSA_CERT:
return "ssh-rsa-cert-v01@openssh.com";
case KEY_DSA_CERT:
return "ssh-dss-cert-v01@openssh.com";
} }
return "ssh-unknown"; return "ssh-unknown";
} }
@ -836,9 +860,11 @@ key_size(const Key *k)
switch (k->type) { switch (k->type) {
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
return BN_num_bits(k->rsa->n); return BN_num_bits(k->rsa->n);
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
return BN_num_bits(k->dsa->p); return BN_num_bits(k->dsa->p);
} }
@ -882,6 +908,8 @@ key_generate(int type, u_int bits)
case KEY_RSA1: case KEY_RSA1:
k->rsa = rsa_generate_private_key(bits); k->rsa = rsa_generate_private_key(bits);
break; break;
case KEY_RSA_CERT_V00:
case KEY_DSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
case KEY_DSA_CERT: case KEY_DSA_CERT:
fatal("key_generate: cert keys cannot be generated directly"); fatal("key_generate: cert keys cannot be generated directly");
@ -912,9 +940,12 @@ key_cert_copy(const Key *from_key, struct Key *to_key)
buffer_append(&to->certblob, buffer_ptr(&from->certblob), buffer_append(&to->certblob, buffer_ptr(&from->certblob),
buffer_len(&from->certblob)); buffer_len(&from->certblob));
buffer_append(&to->constraints, buffer_ptr(&from->constraints), buffer_append(&to->critical,
buffer_len(&from->constraints)); buffer_ptr(&from->critical), buffer_len(&from->critical));
buffer_append(&to->extensions,
buffer_ptr(&from->extensions), buffer_len(&from->extensions));
to->serial = from->serial;
to->type = from->type; to->type = from->type;
to->key_id = from->key_id == NULL ? NULL : xstrdup(from->key_id); to->key_id = from->key_id == NULL ? NULL : xstrdup(from->key_id);
to->valid_after = from->valid_after; to->valid_after = from->valid_after;
@ -940,6 +971,7 @@ key_from_private(const Key *k)
Key *n = NULL; Key *n = NULL;
switch (k->type) { switch (k->type) {
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
n = key_new(k->type); n = key_new(k->type);
if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) || if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) ||
@ -950,6 +982,7 @@ key_from_private(const Key *k)
break; break;
case KEY_RSA: case KEY_RSA:
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
n = key_new(k->type); n = key_new(k->type);
if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) || if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
@ -979,8 +1012,12 @@ key_type_from_name(char *name)
} else if (strcmp(name, "ssh-dss") == 0) { } else if (strcmp(name, "ssh-dss") == 0) {
return KEY_DSA; return KEY_DSA;
} else if (strcmp(name, "ssh-rsa-cert-v00@openssh.com") == 0) { } else if (strcmp(name, "ssh-rsa-cert-v00@openssh.com") == 0) {
return KEY_RSA_CERT; return KEY_RSA_CERT_V00;
} else if (strcmp(name, "ssh-dss-cert-v00@openssh.com") == 0) { } else if (strcmp(name, "ssh-dss-cert-v00@openssh.com") == 0) {
return KEY_DSA_CERT_V00;
} else if (strcmp(name, "ssh-rsa-cert-v01@openssh.com") == 0) {
return KEY_RSA_CERT;
} else if (strcmp(name, "ssh-dss-cert-v01@openssh.com") == 0) {
return KEY_DSA_CERT; return KEY_DSA_CERT;
} }
debug2("key_type_from_name: unknown key type '%s'", name); debug2("key_type_from_name: unknown key type '%s'", name);
@ -1012,26 +1049,31 @@ key_names_valid2(const char *names)
static int static int
cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen) cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen)
{ {
u_char *principals, *constraints, *sig_key, *sig; u_char *principals, *critical, *exts, *sig_key, *sig;
u_int signed_len, plen, clen, sklen, slen, kidlen; u_int signed_len, plen, clen, sklen, slen, kidlen, elen;
Buffer tmp; Buffer tmp;
char *principal; char *principal;
int ret = -1; int ret = -1;
int v00 = key->type == KEY_DSA_CERT_V00 ||
key->type == KEY_RSA_CERT_V00;
buffer_init(&tmp); buffer_init(&tmp);
/* Copy the entire key blob for verification and later serialisation */ /* Copy the entire key blob for verification and later serialisation */
buffer_append(&key->cert->certblob, blob, blen); buffer_append(&key->cert->certblob, blob, blen);
principals = constraints = sig_key = sig = NULL; elen = 0; /* Not touched for v00 certs */
if (buffer_get_int_ret(&key->cert->type, b) != 0 || principals = exts = critical = sig_key = sig = NULL;
if ((!v00 && buffer_get_int64_ret(&key->cert->serial, b) != 0) ||
buffer_get_int_ret(&key->cert->type, b) != 0 ||
(key->cert->key_id = buffer_get_string_ret(b, &kidlen)) == NULL || (key->cert->key_id = buffer_get_string_ret(b, &kidlen)) == NULL ||
(principals = buffer_get_string_ret(b, &plen)) == NULL || (principals = buffer_get_string_ret(b, &plen)) == NULL ||
buffer_get_int64_ret(&key->cert->valid_after, b) != 0 || buffer_get_int64_ret(&key->cert->valid_after, b) != 0 ||
buffer_get_int64_ret(&key->cert->valid_before, b) != 0 || buffer_get_int64_ret(&key->cert->valid_before, b) != 0 ||
(constraints = buffer_get_string_ret(b, &clen)) == NULL || (critical = buffer_get_string_ret(b, &clen)) == NULL ||
/* skip nonce */ buffer_get_string_ptr_ret(b, NULL) == NULL || (!v00 && (exts = buffer_get_string_ret(b, &elen)) == NULL) ||
/* skip reserved */ buffer_get_string_ptr_ret(b, NULL) == NULL || (v00 && buffer_get_string_ptr_ret(b, NULL) == NULL) || /* nonce */
buffer_get_string_ptr_ret(b, NULL) == NULL || /* reserved */
(sig_key = buffer_get_string_ret(b, &sklen)) == NULL) { (sig_key = buffer_get_string_ret(b, &sklen)) == NULL) {
error("%s: parse error", __func__); error("%s: parse error", __func__);
goto out; goto out;
@ -1078,13 +1120,25 @@ cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen)
buffer_clear(&tmp); buffer_clear(&tmp);
buffer_append(&key->cert->constraints, constraints, clen); buffer_append(&key->cert->critical, critical, clen);
buffer_append(&tmp, constraints, clen); buffer_append(&tmp, critical, clen);
/* validate structure */ /* validate structure */
while (buffer_len(&tmp) != 0) { while (buffer_len(&tmp) != 0) {
if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL || if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL ||
buffer_get_string_ptr_ret(&tmp, NULL) == NULL) { buffer_get_string_ptr_ret(&tmp, NULL) == NULL) {
error("%s: Constraints data invalid", __func__); error("%s: critical option data invalid", __func__);
goto out;
}
}
buffer_clear(&tmp);
buffer_append(&key->cert->extensions, exts, elen);
buffer_append(&tmp, exts, elen);
/* validate structure */
while (buffer_len(&tmp) != 0) {
if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL ||
buffer_get_string_ptr_ret(&tmp, NULL) == NULL) {
error("%s: extension data invalid", __func__);
goto out; goto out;
} }
} }
@ -1121,8 +1175,10 @@ cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen)
buffer_free(&tmp); buffer_free(&tmp);
if (principals != NULL) if (principals != NULL)
xfree(principals); xfree(principals);
if (constraints != NULL) if (critical != NULL)
xfree(constraints); xfree(critical);
if (exts != NULL)
xfree(exts);
if (sig_key != NULL) if (sig_key != NULL)
xfree(sig_key); xfree(sig_key);
if (sig != NULL) if (sig != NULL)
@ -1151,8 +1207,11 @@ key_from_blob(const u_char *blob, u_int blen)
type = key_type_from_name(ktype); type = key_type_from_name(ktype);
switch (type) { switch (type) {
case KEY_RSA:
case KEY_RSA_CERT: case KEY_RSA_CERT:
(void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
/* FALLTHROUGH */
case KEY_RSA:
case KEY_RSA_CERT_V00:
key = key_new(type); key = key_new(type);
if (buffer_get_bignum2_ret(&b, key->rsa->e) == -1 || if (buffer_get_bignum2_ret(&b, key->rsa->e) == -1 ||
buffer_get_bignum2_ret(&b, key->rsa->n) == -1) { buffer_get_bignum2_ret(&b, key->rsa->n) == -1) {
@ -1166,8 +1225,11 @@ key_from_blob(const u_char *blob, u_int blen)
RSA_print_fp(stderr, key->rsa, 8); RSA_print_fp(stderr, key->rsa, 8);
#endif #endif
break; break;
case KEY_DSA:
case KEY_DSA_CERT: case KEY_DSA_CERT:
(void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
/* FALLTHROUGH */
case KEY_DSA:
case KEY_DSA_CERT_V00:
key = key_new(type); key = key_new(type);
if (buffer_get_bignum2_ret(&b, key->dsa->p) == -1 || if (buffer_get_bignum2_ret(&b, key->dsa->p) == -1 ||
buffer_get_bignum2_ret(&b, key->dsa->q) == -1 || buffer_get_bignum2_ret(&b, key->dsa->q) == -1 ||
@ -1213,6 +1275,8 @@ key_to_blob(const Key *key, u_char **blobp, u_int *lenp)
} }
buffer_init(&b); buffer_init(&b);
switch (key->type) { switch (key->type) {
case KEY_DSA_CERT_V00:
case KEY_RSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
case KEY_RSA_CERT: case KEY_RSA_CERT:
/* Use the existing blob */ /* Use the existing blob */
@ -1255,9 +1319,11 @@ key_sign(
const u_char *data, u_int datalen) const u_char *data, u_int datalen)
{ {
switch (key->type) { switch (key->type) {
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
case KEY_DSA: case KEY_DSA:
return ssh_dss_sign(key, sigp, lenp, data, datalen); return ssh_dss_sign(key, sigp, lenp, data, datalen);
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
case KEY_RSA: case KEY_RSA:
return ssh_rsa_sign(key, sigp, lenp, data, datalen); return ssh_rsa_sign(key, sigp, lenp, data, datalen);
@ -1281,9 +1347,11 @@ key_verify(
return -1; return -1;
switch (key->type) { switch (key->type) {
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
case KEY_DSA: case KEY_DSA:
return ssh_dss_verify(key, signature, signaturelen, data, datalen); return ssh_dss_verify(key, signature, signaturelen, data, datalen);
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
case KEY_RSA: case KEY_RSA:
return ssh_rsa_verify(key, signature, signaturelen, data, datalen); return ssh_rsa_verify(key, signature, signaturelen, data, datalen);
@ -1306,6 +1374,7 @@ key_demote(const Key *k)
pk->rsa = NULL; pk->rsa = NULL;
switch (k->type) { switch (k->type) {
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
key_cert_copy(k, pk); key_cert_copy(k, pk);
/* FALLTHROUGH */ /* FALLTHROUGH */
@ -1318,6 +1387,7 @@ key_demote(const Key *k)
if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL) if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL)
fatal("key_demote: BN_dup failed"); fatal("key_demote: BN_dup failed");
break; break;
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
key_cert_copy(k, pk); key_cert_copy(k, pk);
/* FALLTHROUGH */ /* FALLTHROUGH */
@ -1344,8 +1414,17 @@ key_demote(const Key *k)
int int
key_is_cert(const Key *k) key_is_cert(const Key *k)
{ {
return k != NULL && if (k == NULL)
(k->type == KEY_RSA_CERT || k->type == KEY_DSA_CERT); return 0;
switch (k->type) {
case KEY_RSA_CERT_V00:
case KEY_DSA_CERT_V00:
case KEY_RSA_CERT:
case KEY_DSA_CERT:
return 1;
default:
return 0;
}
} }
/* Return the cert-less equivalent to a certified key type */ /* Return the cert-less equivalent to a certified key type */
@ -1353,8 +1432,10 @@ int
key_type_plain(int type) key_type_plain(int type)
{ {
switch (type) { switch (type) {
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
return KEY_RSA; return KEY_RSA;
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
return KEY_DSA; return KEY_DSA;
default: default:
@ -1364,16 +1445,16 @@ key_type_plain(int type)
/* Convert a KEY_RSA or KEY_DSA to their _CERT equivalent */ /* Convert a KEY_RSA or KEY_DSA to their _CERT equivalent */
int int
key_to_certified(Key *k) key_to_certified(Key *k, int legacy)
{ {
switch (k->type) { switch (k->type) {
case KEY_RSA: case KEY_RSA:
k->cert = cert_new(); k->cert = cert_new();
k->type = KEY_RSA_CERT; k->type = legacy ? KEY_RSA_CERT_V00 : KEY_RSA_CERT;
return 0; return 0;
case KEY_DSA: case KEY_DSA:
k->cert = cert_new(); k->cert = cert_new();
k->type = KEY_DSA_CERT; k->type = legacy ? KEY_DSA_CERT_V00 : KEY_DSA_CERT;
return 0; return 0;
default: default:
error("%s: key has incorrect type %s", __func__, key_type(k)); error("%s: key has incorrect type %s", __func__, key_type(k));
@ -1386,10 +1467,12 @@ int
key_drop_cert(Key *k) key_drop_cert(Key *k)
{ {
switch (k->type) { switch (k->type) {
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
cert_free(k->cert); cert_free(k->cert);
k->type = KEY_RSA; k->type = KEY_RSA;
return 0; return 0;
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
cert_free(k->cert); cert_free(k->cert);
k->type = KEY_DSA; k->type = KEY_DSA;
@ -1430,13 +1513,21 @@ key_certify(Key *k, Key *ca)
buffer_clear(&k->cert->certblob); buffer_clear(&k->cert->certblob);
buffer_put_cstring(&k->cert->certblob, key_ssh_name(k)); buffer_put_cstring(&k->cert->certblob, key_ssh_name(k));
/* -v01 certs put nonce first */
if (k->type == KEY_DSA_CERT || k->type == KEY_RSA_CERT) {
arc4random_buf(&nonce, sizeof(nonce));
buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce));
}
switch (k->type) { switch (k->type) {
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
buffer_put_bignum2(&k->cert->certblob, k->dsa->p); buffer_put_bignum2(&k->cert->certblob, k->dsa->p);
buffer_put_bignum2(&k->cert->certblob, k->dsa->q); buffer_put_bignum2(&k->cert->certblob, k->dsa->q);
buffer_put_bignum2(&k->cert->certblob, k->dsa->g); buffer_put_bignum2(&k->cert->certblob, k->dsa->g);
buffer_put_bignum2(&k->cert->certblob, k->dsa->pub_key); buffer_put_bignum2(&k->cert->certblob, k->dsa->pub_key);
break; break;
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
buffer_put_bignum2(&k->cert->certblob, k->rsa->e); buffer_put_bignum2(&k->cert->certblob, k->rsa->e);
buffer_put_bignum2(&k->cert->certblob, k->rsa->n); buffer_put_bignum2(&k->cert->certblob, k->rsa->n);
@ -1448,6 +1539,10 @@ key_certify(Key *k, Key *ca)
return -1; return -1;
} }
/* -v01 certs have a serial number next */
if (k->type == KEY_DSA_CERT || k->type == KEY_RSA_CERT)
buffer_put_int64(&k->cert->certblob, k->cert->serial);
buffer_put_int(&k->cert->certblob, k->cert->type); buffer_put_int(&k->cert->certblob, k->cert->type);
buffer_put_cstring(&k->cert->certblob, k->cert->key_id); buffer_put_cstring(&k->cert->certblob, k->cert->key_id);
@ -1461,11 +1556,19 @@ key_certify(Key *k, Key *ca)
buffer_put_int64(&k->cert->certblob, k->cert->valid_after); buffer_put_int64(&k->cert->certblob, k->cert->valid_after);
buffer_put_int64(&k->cert->certblob, k->cert->valid_before); buffer_put_int64(&k->cert->certblob, k->cert->valid_before);
buffer_put_string(&k->cert->certblob, buffer_put_string(&k->cert->certblob,
buffer_ptr(&k->cert->constraints), buffer_ptr(&k->cert->critical), buffer_len(&k->cert->critical));
buffer_len(&k->cert->constraints));
/* -v01 certs have non-critical options here */
if (k->type == KEY_DSA_CERT || k->type == KEY_RSA_CERT) {
buffer_put_string(&k->cert->certblob,
buffer_ptr(&k->cert->extensions),
buffer_len(&k->cert->extensions));
}
/* -v00 certs put the nonce at the end */
if (k->type == KEY_DSA_CERT_V00 || k->type == KEY_RSA_CERT_V00)
buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce));
arc4random_buf(&nonce, sizeof(nonce));
buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce));
buffer_put_string(&k->cert->certblob, NULL, 0); /* reserved */ buffer_put_string(&k->cert->certblob, NULL, 0); /* reserved */
buffer_put_string(&k->cert->certblob, ca_blob, ca_len); buffer_put_string(&k->cert->certblob, ca_blob, ca_len);
xfree(ca_blob); xfree(ca_blob);
@ -1536,3 +1639,15 @@ key_cert_check_authority(const Key *k, int want_host, int require_principal,
} }
return 0; return 0;
} }
int
key_cert_is_legacy(Key *k)
{
switch (k->type) {
case KEY_DSA_CERT_V00:
case KEY_RSA_CERT_V00:
return 1;
default:
return 0;
}
}

11
key.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: key.h,v 1.29 2010/03/15 19:40:02 stevesk Exp $ */ /* $OpenBSD: key.h,v 1.30 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -37,6 +37,8 @@ enum types {
KEY_DSA, KEY_DSA,
KEY_RSA_CERT, KEY_RSA_CERT,
KEY_DSA_CERT, KEY_DSA_CERT,
KEY_RSA_CERT_V00,
KEY_DSA_CERT_V00,
KEY_UNSPEC KEY_UNSPEC
}; };
enum fp_type { enum fp_type {
@ -56,11 +58,13 @@ enum fp_rep {
struct KeyCert { struct KeyCert {
Buffer certblob; /* Kept around for use on wire */ Buffer certblob; /* Kept around for use on wire */
u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */ u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */
u_int64_t serial;
char *key_id; char *key_id;
u_int nprincipals; u_int nprincipals;
char **principals; char **principals;
u_int64_t valid_after, valid_before; u_int64_t valid_after, valid_before;
Buffer constraints; Buffer critical;
Buffer extensions;
Key *signature_key; Key *signature_key;
}; };
@ -92,12 +96,13 @@ Key *key_from_private(const Key *);
int key_type_from_name(char *); int key_type_from_name(char *);
int key_is_cert(const Key *); int key_is_cert(const Key *);
int key_type_plain(int); int key_type_plain(int);
int key_to_certified(Key *); int key_to_certified(Key *, int);
int key_drop_cert(Key *); int key_drop_cert(Key *);
int key_certify(Key *, Key *); int key_certify(Key *, Key *);
void key_cert_copy(const Key *, struct Key *); void key_cert_copy(const Key *, struct Key *);
int key_cert_check_authority(const Key *, int, int, const char *, int key_cert_check_authority(const Key *, int, int, const char *,
const char **); const char **);
int key_cert_is_legacy(Key *);
Key *key_from_blob(const u_char *, u_int); Key *key_from_blob(const u_char *, u_int);
int key_to_blob(const Key *, u_char **, u_int *); int key_to_blob(const Key *, u_char **, u_int *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: myproposal.h,v 1.24 2010/02/26 20:29:54 djm Exp $ */ /* $OpenBSD: myproposal.h,v 1.25 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -40,9 +40,12 @@
"diffie-hellman-group1-sha1" "diffie-hellman-group1-sha1"
#endif #endif
#define KEX_DEFAULT_PK_ALG "ssh-rsa-cert-v00@openssh.com," \ #define KEX_DEFAULT_PK_ALG \
"ssh-dss-cert-v00@openssh.com," \ "ssh-rsa-cert-v01@openssh.com," \
"ssh-rsa,ssh-dss" "ssh-dss-cert-v01@openssh.com," \
"ssh-rsa-cert-v00@openssh.com," \
"ssh-dss-cert-v00@openssh.com," \
"ssh-rsa,ssh-dss"
#define KEX_DEFAULT_ENCRYPT \ #define KEX_DEFAULT_ENCRYPT \
"aes128-ctr,aes192-ctr,aes256-ctr," \ "aes128-ctr,aes192-ctr,aes256-ctr," \

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-add.c,v 1.94 2010/03/01 11:07:06 otto Exp $ */ /* $OpenBSD: ssh-add.c,v 1.95 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -204,7 +204,7 @@ add_file(AuthenticationConnection *ac, const char *filename)
xasprintf(&certpath, "%s-cert.pub", filename); xasprintf(&certpath, "%s-cert.pub", filename);
if ((cert = key_load_public(certpath, NULL)) != NULL) { if ((cert = key_load_public(certpath, NULL)) != NULL) {
/* Graft with private bits */ /* Graft with private bits */
if (key_to_certified(private) != 0) if (key_to_certified(private, key_cert_is_legacy(cert)) != 0)
fatal("%s: key_to_certified failed", __func__); fatal("%s: key_to_certified failed", __func__);
key_cert_copy(cert, private); key_cert_copy(cert, private);
key_free(cert); key_free(cert);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-agent.c,v 1.165 2010/02/26 20:29:54 djm Exp $ */ /* $OpenBSD: ssh-agent.c,v 1.166 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -500,6 +500,7 @@ process_add_identity(SocketEntry *e, int version)
buffer_get_bignum2(&e->request, k->dsa->pub_key); buffer_get_bignum2(&e->request, k->dsa->pub_key);
buffer_get_bignum2(&e->request, k->dsa->priv_key); buffer_get_bignum2(&e->request, k->dsa->priv_key);
break; break;
case KEY_DSA_CERT_V00:
case KEY_DSA_CERT: case KEY_DSA_CERT:
cert = buffer_get_string(&e->request, &len); cert = buffer_get_string(&e->request, &len);
if ((k = key_from_blob(cert, len)) == NULL) if ((k = key_from_blob(cert, len)) == NULL)
@ -520,6 +521,7 @@ process_add_identity(SocketEntry *e, int version)
/* Generate additional parameters */ /* Generate additional parameters */
rsa_generate_additional_parameters(k->rsa); rsa_generate_additional_parameters(k->rsa);
break; break;
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
cert = buffer_get_string(&e->request, &len); cert = buffer_get_string(&e->request, &len);
if ((k = key_from_blob(cert, len)) == NULL) if ((k = key_from_blob(cert, len)) == NULL)
@ -540,6 +542,7 @@ process_add_identity(SocketEntry *e, int version)
/* enable blinding */ /* enable blinding */
switch (k->type) { switch (k->type) {
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
case KEY_RSA1: case KEY_RSA1:
if (RSA_blinding_on(k->rsa, NULL) != 1) { if (RSA_blinding_on(k->rsa, NULL) != 1) {

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-dss.c,v 1.25 2010/02/26 20:29:54 djm Exp $ */ /* $OpenBSD: ssh-dss.c,v 1.26 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -53,9 +53,8 @@ ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp,
u_int rlen, slen, len, dlen; u_int rlen, slen, len, dlen;
Buffer b; Buffer b;
if (key == NULL || if (key == NULL || key->dsa == NULL || (key->type != KEY_DSA &&
(key->type != KEY_DSA && key->type != KEY_DSA_CERT) || key->type != KEY_DSA_CERT && key->type != KEY_DSA_CERT_V00)) {
key->dsa == NULL) {
error("ssh_dss_sign: no DSA key"); error("ssh_dss_sign: no DSA key");
return -1; return -1;
} }
@ -118,9 +117,8 @@ ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen,
int rlen, ret; int rlen, ret;
Buffer b; Buffer b;
if (key == NULL || if (key == NULL || key->dsa == NULL || (key->type != KEY_DSA &&
(key->type != KEY_DSA && key->type != KEY_DSA_CERT) || key->type != KEY_DSA_CERT && key->type != KEY_DSA_CERT_V00)) {
key->dsa == NULL) {
error("ssh_dss_verify: no DSA key"); error("ssh_dss_verify: no DSA key");
return -1; return -1;
} }

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-keygen.1,v 1.92 2010/03/13 23:38:13 jmc Exp $ .\" $OpenBSD: ssh-keygen.1,v 1.93 2010/04/16 01:47:26 djm Exp $
.\" .\"
.\" -*- nroff -*- .\" -*- nroff -*-
.\" .\"
@ -37,7 +37,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd $Mdocdate: March 13 2010 $ .Dd $Mdocdate: April 16 2010 $
.Dt SSH-KEYGEN 1 .Dt SSH-KEYGEN 1
.Os .Os
.Sh NAME .Sh NAME
@ -110,8 +110,9 @@
.Fl I Ar certificate_identity .Fl I Ar certificate_identity
.Op Fl h .Op Fl h
.Op Fl n Ar principals .Op Fl n Ar principals
.Op Fl O Ar constraint .Op Fl O Ar option
.Op Fl V Ar validity_interval .Op Fl V Ar validity_interval
.Op Fl z Ar serial_number
.Ar .Ar
.Nm ssh-keygen .Nm ssh-keygen
.Fl L .Fl L
@ -299,13 +300,13 @@ Multiple principals may be specified, separated by commas.
Please see the Please see the
.Sx CERTIFICATES .Sx CERTIFICATES
section for details. section for details.
.It Fl O Ar constraint .It Fl O Ar option
Specify a certificate constraint when signing a key. Specify a certificate option when signing a key.
This option may be specified multiple times. This option may be specified multiple times.
Please see the Please see the
.Sx CERTIFICATES .Sx CERTIFICATES
section for details. section for details.
The constraints that are valid for user certificates are: The options that are valid for user certificates are:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Ic clear .It Ic clear
Clear all enabled permissions. Clear all enabled permissions.
@ -355,7 +356,7 @@ is a comma-separated list of one or more address/netmask pairs in CIDR
format. format.
.El .El
.Pp .Pp
At present, no constraints are valid for host keys. At present, no options are valid for host keys.
.It Fl P Ar passphrase .It Fl P Ar passphrase
Provides the (old) passphrase. Provides the (old) passphrase.
.It Fl p .It Fl p
@ -441,6 +442,10 @@ Specify desired generator when testing candidate moduli for DH-GEX.
.It Fl y .It Fl y
This option will read a private This option will read a private
OpenSSH format file and print an OpenSSH public key to stdout. OpenSSH format file and print an OpenSSH public key to stdout.
.It Fl z Ar serial_number
Specifies a serial number to be embedded in the certificate to distinguish
this certificate from others from the same CA.
The default serial number is zero.
.El .El
.Sh MODULI GENERATION .Sh MODULI GENERATION
.Nm .Nm
@ -501,7 +506,7 @@ that both ends of a connection share common moduli.
supports signing of keys to produce certificates that may be used for supports signing of keys to produce certificates that may be used for
user or host authentication. user or host authentication.
Certificates consist of a public key, some identity information, zero or Certificates consist of a public key, some identity information, zero or
more principal (user or host) names and an optional set of constraints that more principal (user or host) names and an optional set of options that
are signed by a Certification Authority (CA) key. are signed by a Certification Authority (CA) key.
Clients or servers may then trust only the CA key and verify its signature Clients or servers may then trust only the CA key and verify its signature
on a certificate rather than trusting many user/host keys. on a certificate rather than trusting many user/host keys.
@ -541,11 +546,11 @@ To generate a certificate for a specified set of principals:
.Dl "$ ssh-keygen -s ca_key -I key_id -h -n host.domain user_key.pub" .Dl "$ ssh-keygen -s ca_key -I key_id -h -n host.domain user_key.pub"
.Pp .Pp
Additional limitations on the validity and use of user certificates may Additional limitations on the validity and use of user certificates may
be specified through certificate constraints. be specified through certificate options..
A constrained certificate may disable features of the SSH session, may be A certificate option may disable features of the SSH session, may be
valid only when presented from particular source addresses or may valid only when presented from particular source addresses or may
force the use of a specific command. force the use of a specific command.
For a list of valid certificate constraints, see the documentation for the For a list of valid certificate options, see the documentation for the
.Fl O .Fl O
option above. option above.
.Pp .Pp

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keygen.c,v 1.185 2010/03/15 19:40:02 stevesk Exp $ */ /* $OpenBSD: ssh-keygen.c,v 1.186 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -105,6 +105,9 @@ char *identity_comment = NULL;
/* Path to CA key when certifying keys. */ /* Path to CA key when certifying keys. */
char *ca_key_path = NULL; char *ca_key_path = NULL;
/* Certificate serial number */
long long cert_serial = 0;
/* Key type when certifying */ /* Key type when certifying */
u_int cert_key_type = SSH2_CERT_TYPE_USER; u_int cert_key_type = SSH2_CERT_TYPE_USER;
@ -118,18 +121,18 @@ char *cert_principals = NULL;
u_int64_t cert_valid_from = 0; u_int64_t cert_valid_from = 0;
u_int64_t cert_valid_to = ~0ULL; u_int64_t cert_valid_to = ~0ULL;
/* Certificate constraints */ /* Certificate options */
#define CONSTRAINT_X_FWD (1) #define CRITOPT_X_FWD (1)
#define CONSTRAINT_AGENT_FWD (1<<1) #define CRITOPT_AGENT_FWD (1<<1)
#define CONSTRAINT_PORT_FWD (1<<2) #define CRITOPT_PORT_FWD (1<<2)
#define CONSTRAINT_PTY (1<<3) #define CRITOPT_PTY (1<<3)
#define CONSTRAINT_USER_RC (1<<4) #define CRITOPT_USER_RC (1<<4)
#define CONSTRAINT_DEFAULT (CONSTRAINT_X_FWD|CONSTRAINT_AGENT_FWD| \ #define CRITOPT_DEFAULT (CRITOPT_X_FWD|CRITOPT_AGENT_FWD| \
CONSTRAINT_PORT_FWD|CONSTRAINT_PTY| \ CRITOPT_PORT_FWD|CRITOPT_PTY| \
CONSTRAINT_USER_RC) CRITOPT_USER_RC)
u_int32_t constraint_flags = CONSTRAINT_DEFAULT; u_int32_t critical_flags = CRITOPT_DEFAULT;
char *constraint_command = NULL; char *critical_command = NULL;
char *constraint_src_addr = NULL; char *critical_src_addr = NULL;
/* Dump public key file in format used by real and the original SSH 2 */ /* Dump public key file in format used by real and the original SSH 2 */
int convert_to_ssh2 = 0; int convert_to_ssh2 = 0;
@ -161,9 +164,13 @@ ask_filename(struct passwd *pw, const char *prompt)
case KEY_RSA1: case KEY_RSA1:
name = _PATH_SSH_CLIENT_IDENTITY; name = _PATH_SSH_CLIENT_IDENTITY;
break; break;
case KEY_DSA_CERT:
case KEY_DSA_CERT_V00:
case KEY_DSA: case KEY_DSA:
name = _PATH_SSH_CLIENT_ID_DSA; name = _PATH_SSH_CLIENT_ID_DSA;
break; break;
case KEY_RSA_CERT:
case KEY_RSA_CERT_V00:
case KEY_RSA: case KEY_RSA:
name = _PATH_SSH_CLIENT_ID_RSA; name = _PATH_SSH_CLIENT_ID_RSA;
break; break;
@ -1104,7 +1111,7 @@ fmt_validity(u_int64_t valid_from, u_int64_t valid_to)
} }
static void static void
add_flag_constraint(Buffer *c, const char *name) add_flag_option(Buffer *c, const char *name)
{ {
debug3("%s: %s", __func__, name); debug3("%s: %s", __func__, name);
buffer_put_cstring(c, name); buffer_put_cstring(c, name);
@ -1112,7 +1119,7 @@ add_flag_constraint(Buffer *c, const char *name)
} }
static void static void
add_string_constraint(Buffer *c, const char *name, const char *value) add_string_option(Buffer *c, const char *name, const char *value)
{ {
Buffer b; Buffer b;
@ -1127,24 +1134,23 @@ add_string_constraint(Buffer *c, const char *name, const char *value)
} }
static void static void
prepare_constraint_buf(Buffer *c) prepare_options_buf(Buffer *c)
{ {
buffer_clear(c); buffer_clear(c);
if ((constraint_flags & CONSTRAINT_X_FWD) != 0) if ((critical_flags & CRITOPT_X_FWD) != 0)
add_flag_constraint(c, "permit-X11-forwarding"); add_flag_option(c, "permit-X11-forwarding");
if ((constraint_flags & CONSTRAINT_AGENT_FWD) != 0) if ((critical_flags & CRITOPT_AGENT_FWD) != 0)
add_flag_constraint(c, "permit-agent-forwarding"); add_flag_option(c, "permit-agent-forwarding");
if ((constraint_flags & CONSTRAINT_PORT_FWD) != 0) if ((critical_flags & CRITOPT_PORT_FWD) != 0)
add_flag_constraint(c, "permit-port-forwarding"); add_flag_option(c, "permit-port-forwarding");
if ((constraint_flags & CONSTRAINT_PTY) != 0) if ((critical_flags & CRITOPT_PTY) != 0)
add_flag_constraint(c, "permit-pty"); add_flag_option(c, "permit-pty");
if ((constraint_flags & CONSTRAINT_USER_RC) != 0) if ((critical_flags & CRITOPT_USER_RC) != 0)
add_flag_constraint(c, "permit-user-rc"); add_flag_option(c, "permit-user-rc");
if (constraint_command != NULL) if (critical_command != NULL)
add_string_constraint(c, "force-command", constraint_command); add_string_option(c, "force-command", critical_command);
if (constraint_src_addr != NULL) if (critical_src_addr != NULL)
add_string_constraint(c, "source-address", constraint_src_addr); add_string_option(c, "source-address", critical_src_addr);
} }
static void static void
@ -1155,12 +1161,32 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
Key *ca, *public; Key *ca, *public;
char *otmp, *tmp, *cp, *out, *comment, **plist = NULL; char *otmp, *tmp, *cp, *out, *comment, **plist = NULL;
FILE *f; FILE *f;
int v00 = 0; /* legacy keys */
tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
if ((ca = load_identity(tmp)) == NULL) if ((ca = load_identity(tmp)) == NULL)
fatal("Couldn't load CA key \"%s\"", tmp); fatal("Couldn't load CA key \"%s\"", tmp);
xfree(tmp); xfree(tmp);
if (key_type_name != NULL) {
switch (key_type_from_name(key_type_name)) {
case KEY_RSA_CERT_V00:
case KEY_DSA_CERT_V00:
v00 = 1;
break;
case KEY_UNSPEC:
if (strcasecmp(key_type_name, "v00") == 0) {
v00 = 1;
break;
} else if (strcasecmp(key_type_name, "v01") == 0)
break;
/* FALLTHROUGH */
default:
fprintf(stderr, "unknown key type %s\n", key_type_name);
exit(1);
}
}
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
/* Split list of principals */ /* Split list of principals */
n = 0; n = 0;
@ -1183,15 +1209,16 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
__func__, tmp, key_type(public)); __func__, tmp, key_type(public));
/* Prepare certificate to sign */ /* Prepare certificate to sign */
if (key_to_certified(public) != 0) if (key_to_certified(public, v00) != 0)
fatal("Could not upgrade key %s to certificate", tmp); fatal("Could not upgrade key %s to certificate", tmp);
public->cert->type = cert_key_type; public->cert->type = cert_key_type;
public->cert->serial = (u_int64_t)cert_serial;
public->cert->key_id = xstrdup(cert_key_id); public->cert->key_id = xstrdup(cert_key_id);
public->cert->nprincipals = n; public->cert->nprincipals = n;
public->cert->principals = plist; public->cert->principals = plist;
public->cert->valid_after = cert_valid_from; public->cert->valid_after = cert_valid_from;
public->cert->valid_before = cert_valid_to; public->cert->valid_before = cert_valid_to;
prepare_constraint_buf(&public->cert->constraints); prepare_options_buf(&public->cert->critical);
public->cert->signature_key = key_from_private(ca); public->cert->signature_key = key_from_private(ca);
if (key_certify(public, ca) != 0) if (key_certify(public, ca) != 0)
@ -1212,13 +1239,14 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
fprintf(f, " %s\n", comment); fprintf(f, " %s\n", comment);
fclose(f); fclose(f);
if (!quiet) if (!quiet) {
logit("Signed %s key %s: id \"%s\"%s%s valid %s", logit("Signed %s key %s: id \"%s\" serial %llu%s%s "
cert_key_type == SSH2_CERT_TYPE_USER?"user":"host", "valid %s", key_cert_type(public),
out, cert_key_id, out, public->cert->key_id, public->cert->serial,
cert_principals != NULL ? " for " : "", cert_principals != NULL ? " for " : "",
cert_principals != NULL ? cert_principals : "", cert_principals != NULL ? cert_principals : "",
fmt_validity(cert_valid_from, cert_valid_to)); fmt_validity(cert_valid_from, cert_valid_to));
}
key_free(public); key_free(public);
xfree(out); xfree(out);
@ -1321,50 +1349,50 @@ parse_cert_times(char *timespec)
} }
static void static void
add_cert_constraint(char *opt) add_cert_option(char *opt)
{ {
char *val; char *val;
if (strcmp(opt, "clear") == 0) if (strcmp(opt, "clear") == 0)
constraint_flags = 0; critical_flags = 0;
else if (strcasecmp(opt, "no-x11-forwarding") == 0) else if (strcasecmp(opt, "no-x11-forwarding") == 0)
constraint_flags &= ~CONSTRAINT_X_FWD; critical_flags &= ~CRITOPT_X_FWD;
else if (strcasecmp(opt, "permit-x11-forwarding") == 0) else if (strcasecmp(opt, "permit-x11-forwarding") == 0)
constraint_flags |= CONSTRAINT_X_FWD; critical_flags |= CRITOPT_X_FWD;
else if (strcasecmp(opt, "no-agent-forwarding") == 0) else if (strcasecmp(opt, "no-agent-forwarding") == 0)
constraint_flags &= ~CONSTRAINT_AGENT_FWD; critical_flags &= ~CRITOPT_AGENT_FWD;
else if (strcasecmp(opt, "permit-agent-forwarding") == 0) else if (strcasecmp(opt, "permit-agent-forwarding") == 0)
constraint_flags |= CONSTRAINT_AGENT_FWD; critical_flags |= CRITOPT_AGENT_FWD;
else if (strcasecmp(opt, "no-port-forwarding") == 0) else if (strcasecmp(opt, "no-port-forwarding") == 0)
constraint_flags &= ~CONSTRAINT_PORT_FWD; critical_flags &= ~CRITOPT_PORT_FWD;
else if (strcasecmp(opt, "permit-port-forwarding") == 0) else if (strcasecmp(opt, "permit-port-forwarding") == 0)
constraint_flags |= CONSTRAINT_PORT_FWD; critical_flags |= CRITOPT_PORT_FWD;
else if (strcasecmp(opt, "no-pty") == 0) else if (strcasecmp(opt, "no-pty") == 0)
constraint_flags &= ~CONSTRAINT_PTY; critical_flags &= ~CRITOPT_PTY;
else if (strcasecmp(opt, "permit-pty") == 0) else if (strcasecmp(opt, "permit-pty") == 0)
constraint_flags |= CONSTRAINT_PTY; critical_flags |= CRITOPT_PTY;
else if (strcasecmp(opt, "no-user-rc") == 0) else if (strcasecmp(opt, "no-user-rc") == 0)
constraint_flags &= ~CONSTRAINT_USER_RC; critical_flags &= ~CRITOPT_USER_RC;
else if (strcasecmp(opt, "permit-user-rc") == 0) else if (strcasecmp(opt, "permit-user-rc") == 0)
constraint_flags |= CONSTRAINT_USER_RC; critical_flags |= CRITOPT_USER_RC;
else if (strncasecmp(opt, "force-command=", 14) == 0) { else if (strncasecmp(opt, "force-command=", 14) == 0) {
val = opt + 14; val = opt + 14;
if (*val == '\0') if (*val == '\0')
fatal("Empty force-command constraint"); fatal("Empty force-command option");
if (constraint_command != NULL) if (critical_command != NULL)
fatal("force-command already specified"); fatal("force-command already specified");
constraint_command = xstrdup(val); critical_command = xstrdup(val);
} else if (strncasecmp(opt, "source-address=", 15) == 0) { } else if (strncasecmp(opt, "source-address=", 15) == 0) {
val = opt + 15; val = opt + 15;
if (*val == '\0') if (*val == '\0')
fatal("Empty source-address constraint"); fatal("Empty source-address option");
if (constraint_src_addr != NULL) if (critical_src_addr != NULL)
fatal("source-address already specified"); fatal("source-address already specified");
if (addr_match_cidr_list(NULL, val) != 0) if (addr_match_cidr_list(NULL, val) != 0)
fatal("Invalid source-address list"); fatal("Invalid source-address list");
constraint_src_addr = xstrdup(val); critical_src_addr = xstrdup(val);
} else } else
fatal("Unsupported certificate constraint \"%s\"", opt); fatal("Unsupported certificate option \"%s\"", opt);
} }
static void static void
@ -1373,9 +1401,9 @@ do_show_cert(struct passwd *pw)
Key *key; Key *key;
struct stat st; struct stat st;
char *key_fp, *ca_fp; char *key_fp, *ca_fp;
Buffer constraints, constraint; Buffer options, option;
u_char *name, *data; u_char *name, *data;
u_int i, dlen; u_int i, dlen, v00;
if (!have_identity) if (!have_identity)
ask_filename(pw, "Enter file in which the key is"); ask_filename(pw, "Enter file in which the key is");
@ -1387,17 +1415,21 @@ do_show_cert(struct passwd *pw)
fatal("%s is not a public key", identity_file); fatal("%s is not a public key", identity_file);
if (!key_is_cert(key)) if (!key_is_cert(key))
fatal("%s is not a certificate", identity_file); fatal("%s is not a certificate", identity_file);
v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00;
key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
ca_fp = key_fingerprint(key->cert->signature_key, ca_fp = key_fingerprint(key->cert->signature_key,
SSH_FP_MD5, SSH_FP_HEX); SSH_FP_MD5, SSH_FP_HEX);
printf("%s:\n", identity_file); printf("%s:\n", identity_file);
printf(" %s %s certificate %s\n", key_type(key), printf(" Type: %s %s certificate\n", key_ssh_name(key),
key_cert_type(key), key_fp); key_cert_type(key));
printf(" Signed by %s CA %s\n", printf(" Public key: %s %s\n", key_type(key), key_fp);
printf(" Signing CA: %s %s\n",
key_type(key->cert->signature_key), ca_fp); key_type(key->cert->signature_key), ca_fp);
printf(" Key ID \"%s\"\n", key->cert->key_id); printf(" Key ID: \"%s\"\n", key->cert->key_id);
if (!v00)
printf(" Serial: %llu\n", key->cert->serial);
printf(" Valid: %s\n", printf(" Valid: %s\n",
fmt_validity(key->cert->valid_after, key->cert->valid_before)); fmt_validity(key->cert->valid_after, key->cert->valid_before));
printf(" Principals: "); printf(" Principals: ");
@ -1409,20 +1441,20 @@ do_show_cert(struct passwd *pw)
key->cert->principals[i]); key->cert->principals[i]);
printf("\n"); printf("\n");
} }
printf(" Constraints: "); printf(" Critical Options: ");
if (buffer_len(&key->cert->constraints) == 0) if (buffer_len(&key->cert->critical) == 0)
printf("(none)\n"); printf("(none)\n");
else { else {
printf("\n"); printf("\n");
buffer_init(&constraints); buffer_init(&options);
buffer_append(&constraints, buffer_append(&options,
buffer_ptr(&key->cert->constraints), buffer_ptr(&key->cert->critical),
buffer_len(&key->cert->constraints)); buffer_len(&key->cert->critical));
buffer_init(&constraint); buffer_init(&option);
while (buffer_len(&constraints) != 0) { while (buffer_len(&options) != 0) {
name = buffer_get_string(&constraints, NULL); name = buffer_get_string(&options, NULL);
data = buffer_get_string_ptr(&constraints, &dlen); data = buffer_get_string_ptr(&options, &dlen);
buffer_append(&constraint, data, dlen); buffer_append(&option, data, dlen);
printf(" %s", name); printf(" %s", name);
if (strcmp(name, "permit-X11-forwarding") == 0 || if (strcmp(name, "permit-X11-forwarding") == 0 ||
strcmp(name, "permit-agent-forwarding") == 0 || strcmp(name, "permit-agent-forwarding") == 0 ||
@ -1432,22 +1464,43 @@ do_show_cert(struct passwd *pw)
printf("\n"); printf("\n");
else if (strcmp(name, "force-command") == 0 || else if (strcmp(name, "force-command") == 0 ||
strcmp(name, "source-address") == 0) { strcmp(name, "source-address") == 0) {
data = buffer_get_string(&constraint, NULL); data = buffer_get_string(&option, NULL);
printf(" %s\n", data); printf(" %s\n", data);
xfree(data); xfree(data);
} else { } else {
printf(" UNKNOWN CONSTRAINT (len %u)\n", printf(" UNKNOWN OPTION (len %u)\n",
buffer_len(&constraint)); buffer_len(&option));
buffer_clear(&constraint); buffer_clear(&option);
} }
xfree(name); xfree(name);
if (buffer_len(&constraint) != 0) if (buffer_len(&option) != 0)
fatal("Constraint corrupt: extra data at end"); fatal("Option corrupt: extra data at end");
}
buffer_free(&option);
buffer_free(&options);
}
if (!v00) {
printf(" Extensions: ");
if (buffer_len(&key->cert->extensions) == 0)
printf("(none)\n");
else {
printf("\n");
buffer_init(&options);
buffer_append(&options,
buffer_ptr(&key->cert->extensions),
buffer_len(&key->cert->extensions));
buffer_init(&option);
while (buffer_len(&options) != 0) {
name = buffer_get_string(&options, NULL);
(void)buffer_get_string_ptr(&options, &dlen);
printf(" %s UNKNOWN OPTION "
"(len %u)\n", name, dlen);
xfree(name);
}
buffer_free(&option);
buffer_free(&options);
} }
buffer_free(&constraint);
buffer_free(&constraints);
} }
exit(0); exit(0);
} }
@ -1478,7 +1531,7 @@ usage(void)
fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n");
fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); fprintf(stderr, " -n name,... User/host principal names to include in certificate\n");
fprintf(stderr, " -N phrase Provide new passphrase.\n"); fprintf(stderr, " -N phrase Provide new passphrase.\n");
fprintf(stderr, " -O cnstr Specify a certificate constraint.\n"); fprintf(stderr, " -O cnstr Specify a certificate option.\n");
fprintf(stderr, " -P phrase Provide old passphrase.\n"); fprintf(stderr, " -P phrase Provide old passphrase.\n");
fprintf(stderr, " -p Change passphrase of private key file.\n"); fprintf(stderr, " -p Change passphrase of private key file.\n");
fprintf(stderr, " -q Quiet.\n"); fprintf(stderr, " -q Quiet.\n");
@ -1541,7 +1594,7 @@ main(int argc, char **argv)
} }
while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:N:n:" while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:N:n:"
"O:C:r:g:R:T:G:M:S:s:a:V:W:")) != -1) { "O:C:r:g:R:T:G:M:S:s:a:V:W:z:")) != -1) {
switch (opt) { switch (opt) {
case 'b': case 'b':
bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr);
@ -1597,7 +1650,7 @@ main(int argc, char **argv)
identity_new_passphrase = optarg; identity_new_passphrase = optarg;
break; break;
case 'O': case 'O':
add_cert_constraint(optarg); add_cert_option(optarg);
break; break;
case 'C': case 'C':
identity_comment = optarg; identity_comment = optarg;
@ -1612,7 +1665,7 @@ main(int argc, char **argv)
break; break;
case 'h': case 'h':
cert_key_type = SSH2_CERT_TYPE_HOST; cert_key_type = SSH2_CERT_TYPE_HOST;
constraint_flags = 0; critical_flags = 0;
break; break;
case 'i': case 'i':
case 'X': case 'X':
@ -1661,9 +1714,8 @@ main(int argc, char **argv)
break; break;
case 'M': case 'M':
memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
if (errstr) { if (errstr)
fatal("Memory limit is %s: %s", errstr, optarg); fatal("Memory limit is %s: %s", errstr, optarg);
}
break; break;
case 'G': case 'G':
do_gen_candidates = 1; do_gen_candidates = 1;
@ -1685,6 +1737,11 @@ main(int argc, char **argv)
case 'V': case 'V':
parse_cert_times(optarg); parse_cert_times(optarg);
break; break;
case 'z':
cert_serial = strtonum(optarg, 0, LLONG_MAX, &errstr);
if (errstr)
fatal("Invalid serial number: %s", errstr);
break;
case '?': case '?':
default: default:
usage(); usage();

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-rsa.c,v 1.40 2010/02/26 20:29:54 djm Exp $ */ /* $OpenBSD: ssh-rsa.c,v 1.41 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
* *
@ -46,9 +46,8 @@ ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp,
int ok, nid; int ok, nid;
Buffer b; Buffer b;
if (key == NULL || if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA &&
(key->type != KEY_RSA && key->type != KEY_RSA_CERT) || key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) {
key->rsa == NULL) {
error("ssh_rsa_sign: no RSA key"); error("ssh_rsa_sign: no RSA key");
return -1; return -1;
} }
@ -115,9 +114,8 @@ ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen,
u_int len, dlen, modlen; u_int len, dlen, modlen;
int rlen, ret, nid; int rlen, ret, nid;
if (key == NULL || if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA &&
(key->type != KEY_RSA && key->type != KEY_RSA_CERT) || key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) {
key->rsa == NULL) {
error("ssh_rsa_verify: no RSA key"); error("ssh_rsa_verify: no RSA key");
return -1; return -1;
} }

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect.c,v 1.222 2010/04/14 22:27:42 djm Exp $ */ /* $OpenBSD: sshconnect.c,v 1.223 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -586,9 +586,9 @@ check_host_cert(const char *host, const Key *host_key)
error("%s", reason); error("%s", reason);
return 0; return 0;
} }
if (buffer_len(&host_key->cert->constraints) != 0) { if (buffer_len(&host_key->cert->critical) != 0) {
error("Certificate for %s contains unsupported constraint(s)", error("Certificate for %s contains unsupported "
host); "critical options(s)", host);
return 0; return 0;
} }
return 1; return 1;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect2.c,v 1.181 2010/04/10 02:10:56 djm Exp $ */ /* $OpenBSD: sshconnect2.c,v 1.182 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved.
@ -1140,8 +1140,11 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
u_int skip = 0; u_int skip = 0;
int ret = -1; int ret = -1;
int have_sig = 1; int have_sig = 1;
char *fp;
debug3("sign_and_send_pubkey"); fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp);
xfree(fp);
if (key_to_blob(id->key, &blob, &bloblen) == 0) { if (key_to_blob(id->key, &blob, &bloblen) == 0) {
/* we cannot handle this key */ /* we cannot handle this key */

15
sshd.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshd.c,v 1.374 2010/03/07 11:57:13 dtucker Exp $ */ /* $OpenBSD: sshd.c,v 1.375 2010/04/16 01:47:26 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -744,6 +744,8 @@ list_hostkey_types(void)
if (key == NULL) if (key == NULL)
continue; continue;
switch (key->type) { switch (key->type) {
case KEY_RSA_CERT_V00:
case KEY_DSA_CERT_V00:
case KEY_RSA_CERT: case KEY_RSA_CERT:
case KEY_DSA_CERT: case KEY_DSA_CERT:
if (buffer_len(&b) > 0) if (buffer_len(&b) > 0)
@ -767,10 +769,17 @@ get_hostkey_by_type(int type, int need_private)
Key *key; Key *key;
for (i = 0; i < options.num_host_key_files; i++) { for (i = 0; i < options.num_host_key_files; i++) {
if (type == KEY_RSA_CERT || type == KEY_DSA_CERT) switch (type) {
case KEY_RSA_CERT_V00:
case KEY_DSA_CERT_V00:
case KEY_RSA_CERT:
case KEY_DSA_CERT:
key = sensitive_data.host_certificates[i]; key = sensitive_data.host_certificates[i];
else break;
default:
key = sensitive_data.host_keys[i]; key = sensitive_data.host_keys[i];
break;
}
if (key != NULL && key->type == type) if (key != NULL && key->type == type)
return need_private ? return need_private ?
sensitive_data.host_keys[i] : key; sensitive_data.host_keys[i] : key;