Certificate Based SSH User Authentication

SSH server can authenticate user based on Certificates. This post describes the process to setup user authentication using Certificates.


Setting Up Certificate Authority Infrastructure


SSHCert1

CA Machine

  • Generate CA key (user_ca) for signing user ssh keys

root@CA:~# ssh-keygen -f user_ca
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in user_ca.
Your public key has been saved in user_ca.pub.
The key fingerprint is:
b3:af:e8:ef:c4:5d:90:f8:be:16:99:74:f2:39:3a:3e root@CA
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|         . .     |
|        . o      |
|         .o..    |
|        S..*..   |
|       . =+.+    |
|        + oo .   |
|       o .E.     |
|     .oo+++o     |
+-----------------+
root@CA:~# ls
user_ca  user_ca.pub

Server Machine

  • Transfer and add CA public key (user_ca.pub) as Trusted Key in the ssh server machines and restart openssh server

# vi /etc/ssh/sshd_config

TrustedUserCAKeys /etc/ssh/user_ca.pub


Authorizing SSH Users


SSHCert2

Client Machine

  • ssh key from user1 is generated (make sure to have a pass-phrase for the key, else it will be rejected during authentication)

user1@client1:~$ ssh-keygen -trsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user1/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user1/.ssh/id_rsa.
Your public key has been saved in /home/user1/.ssh/id_rsa.pub.
The key fingerprint is:
6f:d0:27:36:69:80:e4:ad:0c:5c:f9:d9:d8:af:a9:8d user1@client1
The key's randomart image is:
+---[RSA 2048]----+
|      o.         |
|   . +.o         |
|    o o.o=       |
|     o .+oo.     |
|      o S B..    |
|         = +.    |
|          oo     |
|         +o      |
|        E..      |
+-----------------+

  • ssh key transferred to CA to be signed with user_ca Private Key

user1@client1:~$ scp .ssh/id_rsa.pub root@CA:~/user1_id_rsa.pub
root@ca's password:
id_rsa.pub                                                                                                                               100%  395     0.4KB/s   00:00    

CA Machine

  • User ssh public key signed by CA

ssh-keygen -s user_ca -I user_user1 -n user1 -V +52w user1_id_rsa.pub
Signed user key user1_id_rsa-cert.pub: id "user_user1" serial 0 for user1 valid from 2014-12-30T16:18:00 to 2015-12-29T16:19:57

Client Machine

  • ssh key transferred back to client after signing with user_ca Private Key

user1@client1:~$ scp root@CA:~/user1_id_rsa-cert.pub .ssh/id_rsa.pub
root@ca's password: 


Testing the result


Client Machine

  • Once the above is completed user1 will be able to login to server1 without any password.
user1@client1:~$ ssh user1@server1
Enter passphrase for key '/home/user1/.ssh/id_rsa':
Welcome to Ubuntu Vivid Vervet (development branch) (GNU/Linux 3.13.0-43-generic x86_64)

 * Documentation:  https://help.ubuntu.com/

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

user1@server1:~$

REF: http://blog.habets.pp.se/2011/07/OpenSSH-certificates

SSH Infect

SSH Infect

infect_demo

A script to manage ssh public key install on servers

#!/bin/bash
#set -x

DESTHOST=$1
DB_PATH="$HOME/tmp"
DB_HOST_PREFIX='ssh_key'
packup_dir="${DB_PATH}/$(basename $0)_packup"
bin_dir="$HOME/bin"

which ssh-add >/dev/null 2>&1
SSH_ADD_PRESENT=$?

function list_infected()
{
    cd ${DB_PATH}/
    hosts=`ls ${DB_HOST_PREFIX}* 2>/dev/null`

    for host in $hosts; do
            echo "- ${host##${DB_HOST_PREFIX}_}"
    done
    cd - >/dev/null 2>&1
}

function clear_infected()
{
    cd ${DB_PATH}
    hosts=`ls ${DB_HOST_PREFIX}_$1 2>/dev/null`
    if [[ "$hosts" == "" ]]; then
        echo "No matching record found for host: $1"
        exit 1
    fi
    echo "#=================================================="
    echo "Following hosts will be cleared"
    echo "#=================================================="
    echo ${hosts##${DB_HOST_PREFIX}_}|tr " " "\n"
    echo "#=================================================="
    read -p "Confirm [y/n]: " ans
    if [[ "$ans" == "y" ]]; then
        key=$(awk '{print $NF}' ~/.ssh/id_rsa.pub)
        $(ssh $1 "sed -i \"/$key/d\" ~/.ssh/authorized_keys") && echo "Key removed"
        rm -f $hosts

        ssh_key_test $1
        if [[ "$?" != "0" ]]; then
            echo "Host $1 cleaned"
        fi
    fi
    cd - >/dev/null 2>&1
}

function packup()
{

    rm -rf $packup_dir*
    packup_dir=${packup_dir}_$(date +%F)
    mkdir -p ${packup_dir}/{$(basename ${DB_PATH}),$(basename ${bin_dir})}
    cp -rp ${DB_PATH}/${DB_HOST_PREFIX}* ${packup_dir}/$(basename ${DB_PATH})
    cp -rp $0 ${packup_dir}/$(basename ${bin_dir})
    cp -rp ~/.ssh ${packup_dir}
    tar -czf ${packup_dir}.tgz $packup_dir 2>/dev/null
    echo "Package: ${packup_dir}.tgz"
}

function startup()
{
    if [[ ! -d $DB_PATH ]]; then
        echo "DB path is not present"
        mkdir -p $DB_PATH
    fi

}

function ssh_key_gen()
{
    if [[ ! -f ~/.ssh/id_rsa ]]; then
        [[ $SSH_ADD_PRESENT -eq 0 ]] && ssh-add -D
        ssh-keygen -t rsa -N '' -q -f ~/.ssh/id_rsa
        [[ $SSH_ADD_PRESENT -eq 0 ]] && ssh-add
    fi
}

function ssh_key_test()
{
    ssh -oPasswordAuthentication=no $1 exit 0;
    return $?

}

function ssh_key_copy()
{
    SSH_KEY_COPY_CMD="umask 0022; mkdir -p ~/.ssh; chmod 700 ~/.ssh; cat >> ~/.ssh/authorized_keys"
    ssh_key_test $DESTHOST
    if [[ "$?" != "0" ]]; then
        $(cat ~/.ssh/id_rsa.pub |ssh $DESTHOST $SSH_KEY_COPY_CMD) \
                && touch $DB_PATH/${DB_HOST_PREFIX}_${DESTHOST}
    else
        touch $DB_PATH/${DB_HOST_PREFIX}_${DESTHOST}
    fi
}

#===============START===================#
startup

if [[ "$1" == "-l" ]]; then
    echo "#=================================================="
    echo "Infected hosts"
    echo "#=================================================="
    list_infected
elif [[ "$1" == "-c" ]]; then
    clear_infected $2
elif [[ "$1" == "-p" ]]; then
    echo "#=================================================="
    echo "Packing `basename $0` database"
    echo "#=================================================="
    packup
else
    ssh_key_gen
    ssh_key_copy
fi

Classic Encryption: Vigenère

def gen_list(start):
        li = [chr(i) for i in range(65, 91)]
        return li[start:len(li)] + li[0:start]

def gen_arr():
        arr = []
        for i in range(0, 26):
                arr.append(gen_list(i))
        return arr

def print_arr():
        arr = gen_arr()
        for i in arr:
                print i

def gen_key_repeat(key, length):
        key_len = len(key)
        return key * (length/key_len) + key[:(length%key_len)]

def encrypt_char(in_char, key_char):
        arr = gen_arr()
        x = arr[0].index(in_char)
        for i in range(0, len(arr)):
                if arr[i][0] == key_char:
                        y = i
                        break
        return arr[y][x]

def decrypt_char(en_char, index, key_char):
        arr = gen_arr()
        for i in range(0, len(arr)):
                if arr[i][0] == key_char:
                        y = i
                        break
        x = arr[y].index(en_char)
        return arr[0][x]

def decrypt(input, key):
        key_repeat =  gen_key_repeat(key, len(input))
        arr = gen_arr()
        decrypted = []
        for i in range(0, len(input)):
                decrypted.append(decrypt_char(input[i], i, key_repeat[i]))
        return decrypted

def encrypt(input, key):
        key_repeat =  gen_key_repeat(key, len(input))
        arr = gen_arr()
        encrypted = []
        for i in range(0, len(input)):
                encrypted.append(encrypt_char(input[i], key_repeat[i]))
        return encrypted

key="KEYWORD"
input = raw_input("Input: ")
input = input.replace(" ", "").upper()

print_arr()

encrypted = "".join(encrypt(input, key))
print "Encrypted: ", encrypted

decrypted = "".join(decrypt(encrypted, key))
print "Decrypted: ", decrypted

vig

Classic Encryption: Four Square

Simple encryption based on classic four square


import random

chars = range(65,91)
chars.pop(16)

def make_array(input):
        arr = []
        li = []
        for i in range(0, len(input)):
                if i % 5 == 0 and i:
                        arr.append(li)
                        li = []
                li.append(chr(input[i]))
        arr.append(li)
        return arr

random.shuffle(chars)
b1 = make_array(chars)
random.shuffle(chars)
b2 = make_array(chars)
random.shuffle(chars)
b3 = make_array(chars)
random.shuffle(chars)
b4 = make_array(chars)

def tokenize(input):
        for i in range(0, len(input), 2):
                yield "%s%s" %(input[i], input[i+1])

def find(ch, block):
        for i in range(0, len(block)):
                for j in range(0, len(block[i])):
                        if ch == block[i][j]:
                                return i, j
def encrypt(input):
        first = find(input[0], b1)
        second = find(input[1], b4)
        return "%s%s" %(b2[first[0]][second[1]], b3[second[0]][first[1]])
        return first, second

def decrypt(input):
        first = find(input[0], b2)
        second = find(input[1], b3)
        return "%s%s" %(b1[first[0]][second[1]], b4[second[0]][first[1]])
        return first, second

def print_block():
        for i in range(0, len(b1)):
                print " ".join(b1[i]), "   ", " ".join(b2[i])

        print "\n"
        for i in range(0, len(b1)):
                print " ".join(b3[i]), "   ", " ".join(b4[i])

input = raw_input("Input: ")
input = input.upper()

if len(input) % 2 != 0:
        input = input[:-1]

print_block()

encrypted = "".join([encrypt(i) for i in tokenize(input)])
print "Encrypted: ", encrypted

decrypted = "".join([decrypt(i) for i in tokenize(encrypted)])
print "Decrypted: ", decrypted

fs3 fs2 fs1