From ba550217eee4dc5fa7822340529e6ed2c9faadc3 Mon Sep 17 00:00:00 2001
From: Russell Lewis <russelll@netflix.com>
Date: Fri, 13 Jul 2018 17:37:00 -0700
Subject: [PATCH] =?UTF-8?q?Allowing=20BLESS=20lambda=20to=20accept=20ed255?=
 =?UTF-8?q?19=20keys,=20completing=20https://gith=E2=80=A6=20(#74)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Allowing BLESS lambda to accept ed25519 keys, completing https://github.com/Netflix/bless/pull/71 .  Thanks @jnewbigin .
---
 bless/request/bless_request.py        |  3 ++-
 tests/aws_lambda/test_bless_lambda.py | 21 +++++++++++++++++++--
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/bless/request/bless_request.py b/bless/request/bless_request.py
index ad182a0..7712562 100644
--- a/bless/request/bless_request.py
+++ b/bless/request/bless_request.py
@@ -29,6 +29,7 @@
 # There doesn't seem to be any practical size limits of an SSH Certificate Principal (> 4096B allowed).
 PRINCIPAL_PATTERN = re.compile(r'[\d\w!"$%&\'()*+\-./:;<=>?@\[\\\]\^`{|}~]+\Z')
 VALID_SSH_RSA_PUBLIC_KEY_HEADER = "ssh-rsa AAAAB3NzaC1yc2"
+VALID_SSH_ED25519_PUBLIC_KEY_HEADER = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5"
 
 USERNAME_VALIDATION_OPTIONS = Enum('UserNameValidationOptions',
                                    'useradd '  # Allowable usernames per 'man 8 useradd'
@@ -79,7 +80,7 @@ def _validate_principal(principal):
 
 
 def validate_ssh_public_key(public_key):
-    if public_key.startswith(VALID_SSH_RSA_PUBLIC_KEY_HEADER):
+    if public_key.startswith(VALID_SSH_RSA_PUBLIC_KEY_HEADER) or public_key.startswith(VALID_SSH_ED25519_PUBLIC_KEY_HEADER):
         pass
     # todo other key types
     else:
diff --git a/tests/aws_lambda/test_bless_lambda.py b/tests/aws_lambda/test_bless_lambda.py
index e6816e8..cc1b298 100644
--- a/tests/aws_lambda/test_bless_lambda.py
+++ b/tests/aws_lambda/test_bless_lambda.py
@@ -4,7 +4,7 @@
 
 from bless.aws_lambda.bless_lambda import lambda_handler
 from tests.ssh.vectors import EXAMPLE_RSA_PUBLIC_KEY, RSA_CA_PRIVATE_KEY_PASSWORD, \
-    EXAMPLE_ED25519_PUBLIC_KEY
+    EXAMPLE_ED25519_PUBLIC_KEY, EXAMPLE_ECDSA_PUBLIC_KEY
 
 
 class Context(object):
@@ -21,6 +21,15 @@ class Context(object):
     "bastion_user_ip": "127.0.0.1"
 }
 
+VALID_TEST_REQUEST_ED2551 = {
+    "remote_usernames": "user",
+    "public_key_to_sign": EXAMPLE_ED25519_PUBLIC_KEY,
+    "command": "ssh user@server",
+    "bastion_ips": "127.0.0.1",
+    "bastion_user": "user",
+    "bastion_user_ip": "127.0.0.1"
+}
+
 VALID_TEST_REQUEST_USERNAME_VALIDATION_EMAIL_REMOTE_USERNAMES_USERADD = {
     "remote_usernames": "user,anotheruser",
     "public_key_to_sign": EXAMPLE_RSA_PUBLIC_KEY,
@@ -60,7 +69,7 @@ class Context(object):
 
 INVALID_TEST_REQUEST_KEY_TYPE = {
     "remote_usernames": "user",
-    "public_key_to_sign": EXAMPLE_ED25519_PUBLIC_KEY,
+    "public_key_to_sign": EXAMPLE_ECDSA_PUBLIC_KEY,
     "command": "ssh user@server",
     "bastion_ips": "127.0.0.1",
     "bastion_user": "user",
@@ -153,6 +162,14 @@ def test_basic_local_request():
     assert output['certificate'].startswith('ssh-rsa-cert-v01@openssh.com ')
 
 
+def test_basic_local_request_ed2551():
+    output = lambda_handler(VALID_TEST_REQUEST_ED2551, context=Context,
+                            ca_private_key_password=RSA_CA_PRIVATE_KEY_PASSWORD,
+                            entropy_check=False,
+                            config_file=os.path.join(os.path.dirname(__file__), 'bless-test.cfg'))
+    assert output['certificate'].startswith('ssh-ed25519-cert-v01@openssh.com ')
+
+
 def test_basic_local_unused_kmsauth_request():
     output = lambda_handler(VALID_TEST_REQUEST_KMSAUTH, context=Context,
                             ca_private_key_password=RSA_CA_PRIVATE_KEY_PASSWORD,