summaryrefslogtreecommitdiff
path: root/scripts/rvi_create_device_key.py
blob: 060ea8b68c920cd9d0f9b46e2723ad86841dbe37 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/python

#
# Copyright (C) 2015, Jaguar Land Rover
#
# This program is licensed under the terms and conditions of the
# Mozilla Public License, version 2.0.  T full text of the 
# Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
#
# 
#  1. Generate a device key through openssl.
#  2. Sign the public key using the provided private root key.
#  3. Create a JWT version of the signed device key.
#

import getopt
import sys
from Crypto.PublicKey import RSA 
import json
import base64
import os

# apt-get install python-dev
# apt-get install libffi-dev
# pip install cryptography
# pip install PyJWT

import jwt
import struct

def long2intarr(long_int):
    _bytes = []
    while long_int:
        long_int, r = divmod(long_int, 256)
        _bytes.insert(0, r)
    return _bytes

# copied from https://github.com/rohe/pyjwkest
def long_to_base64(n):
    bys = long2intarr(n)
    data = struct.pack('%sB' % len(bys), *bys)
    if not len(data):
        data = '\x00'
    s = base64.urlsafe_b64encode(data).rstrip(b'=')
    return s

def usage():
    print "Usage:", sys.argv[0], "-p <priv_root_key> -o <prefix> -b <bits>"
    print "  -p <priv_root_key>  Private root key file to sign public device key with."
    print "  -o <prefix>         File name prefix for generated device keys."
    print "  -b <bits>           Device key length. Default 2048."
    sys.exit(255)

opts, args= getopt.getopt(sys.argv[1:], "p:o:b:")

priv_root_key_fname=""
fname_prefix=""
key_lenth=2048
for o, a in opts:
    if o == "-p":
        priv_root_key_fname = a
    elif o == "-b":
        key_length = int(a)
    elif o == "-o":
        fname_prefix = a
    else:
        usage()
        
if priv_root_key_fname == "" or fname_prefix == "":
    usage()


#
# Generate the device RSA key pair
#
new_key = RSA.generate(bits=key_length) 


#
# Create private key file, which also contains the public key.
#
priv_key_fname = "{}_priv.pem".format(fname_prefix)
priv_key_file = open(priv_key_fname, 'w')
priv_key = new_key.exportKey("PEM") 
priv_key_file.write(priv_key)
priv_key_file.close()


# Read the root private key
priv_root_key_file = open(priv_root_key_fname, 'r')
priv_root_key = RSA.importKey(priv_root_key_file.read())
priv_root_key_file.close()


#
# Extract the device public key that we are to sign with the private root key.
# Dump it in a file to be used by rvi_create_certificate.py
#
pub_key_fname = "{}_pub.pem".format(fname_prefix)
pub_key_file = open(pub_key_fname, 'w')
pub_key = new_key.publickey()
pub_key_pem = pub_key.exportKey("PEM") 
pub_key_file.write(pub_key_pem)
pub_key_file.close()

print "pub_key.e = ", pub_key.e
print "pub_key.n = ", pub_key.n

key_obj = { 
    'keys': [{
	"kty": "RSA",
        "alg": "RS256",
        "use": "sig",
        "e": long_to_base64(pub_key.e),
        "n": long_to_base64(pub_key.n)
    }],
}

# Generate a JWT signature based on the pub key and the private root key
signature = jwt.encode(key_obj, priv_root_key.exportKey('PEM'), algorithm='RS256')


# Verify that we can use the public root key to verify the key.
pub_root_key = priv_root_key.publickey().exportKey('PEM')

try: 
    jwt.decode(signature, pub_root_key)
except:
    print "FAILED VERIFICATION!"
    print "The public portion of the generated device key, signed by the provided private root key,"
    print "could not be verified using the public root key."
    os.remove(priv_key_fname)
    sys.exit(0)

#
# Create signed public JWT file
#
pub_sign_key_fname = "{}_pub_sign.jwt".format(fname_prefix)

pub_sign_key_file = open(pub_sign_key_fname, 'w')
pub_sign_key_file.write(signature)
pub_sign_key_file.close()

print "Device private/public key pair stored in:                    ", priv_key_fname
print "Device public-only key stored in:                            ", pub_key_fname
print "Device JWT-formatted public key signed by private "
print "  root key, stored in:                                       ", pub_sign_key_fname
print "Root key used to sign the device public key read from:       ", priv_root_key_fname
print
print "Set rvi node's device_key_pair config parameter to point to: ", priv_root_key_fname
print "Set rvi node's authorize_jwt config parameter to point to:   ", pub_sign_key_fname
print
print "use ./rvi_create_certificate.py ... --device_key={} to include".format(pub_key_fname)
print "device public key in a certificate."