1## @file
2# This tool can be used to generate new RSA 2048 bit private/public key pairs
3# in a PEM file format using OpenSSL command line utilities that are installed
4# on the path specified by the system environment variable OPENSSL_PATH.
5# This tool can also optionally write one or more SHA 256 hashes of 2048 bit
6# public keys to a binary file, write one or more SHA 256 hashes of 2048 bit
7# public keys to a file in a C structure format, and in verbose mode display
8# one or more SHA 256 hashes of 2048 bit public keys in a C structure format
9# on STDOUT.
10# This tool has been tested with OpenSSL 1.0.1e 11 Feb 2013
11#
12# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
13# This program and the accompanying materials
14# are licensed and made available under the terms and conditions of the BSD License
15# which accompanies this distribution.  The full text of the license may be found at
16# http://opensource.org/licenses/bsd-license.php
17#
18# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20#
21
22'''
23Rsa2048Sha256GenerateKeys
24'''
25
26import os
27import sys
28import argparse
29import subprocess
30from Common.BuildVersion import gBUILD_VERSION
31
32#
33# Globals for help information
34#
35__prog__      = 'Rsa2048Sha256GenerateKeys'
36__version__   = '%s Version %s' % (__prog__, '0.9 ' + gBUILD_VERSION)
37__copyright__ = 'Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.'
38__usage__     = '%s [options]' % (__prog__)
39
40
41if __name__ == '__main__':
42  #
43  # Create command line argument parser object
44  #
45  parser = argparse.ArgumentParser(prog=__prog__, version=__version__, usage=__usage__, description=__copyright__, conflict_handler='resolve')
46  group = parser.add_mutually_exclusive_group(required=True)
47  group.add_argument("-o", "--output", dest='OutputFile', type=argparse.FileType('wb'), metavar='filename', nargs='*', help="specify the output private key filename in PEM format")
48  group.add_argument("-i", "--input", dest='InputFile', type=argparse.FileType('rb'), metavar='filename', nargs='*', help="specify the input private key filename in PEM format")
49  parser.add_argument("--public-key-hash", dest='PublicKeyHashFile', type=argparse.FileType('wb'), help="specify the public key hash filename that is SHA 256 hash of 2048 bit RSA public key in binary format")
50  parser.add_argument("--public-key-hash-c", dest='PublicKeyHashCFile', type=argparse.FileType('wb'), help="specify the public key hash filename that is SHA 256 hash of 2048 bit RSA public key in C structure format")
51  parser.add_argument("-v", "--verbose", dest='Verbose', action="store_true", help="increase output messages")
52  parser.add_argument("-q", "--quiet", dest='Quiet', action="store_true", help="reduce output messages")
53  parser.add_argument("--debug", dest='Debug', type=int, metavar='[0-9]', choices=range(0,10), default=0, help="set debug level")
54
55  #
56  # Parse command line arguments
57  #
58  args = parser.parse_args()
59
60  #
61  # Generate file path to Open SSL command
62  #
63  OpenSslCommand = 'openssl'
64  try:
65    OpenSslPath = os.environ['OPENSSL_PATH']
66    OpenSslCommand = os.path.join(OpenSslPath, OpenSslCommand)
67  except:
68    pass
69
70  #
71  # Verify that Open SSL command is available
72  #
73  try:
74    Process = subprocess.Popen('%s version' % (OpenSslCommand), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
75  except:
76    print 'ERROR: Open SSL command not available.  Please verify PATH or set OPENSSL_PATH'
77    sys.exit(1)
78
79  Version = Process.communicate()
80  if Process.returncode <> 0:
81    print 'ERROR: Open SSL command not available.  Please verify PATH or set OPENSSL_PATH'
82    sys.exit(Process.returncode)
83  print Version[0]
84
85  args.PemFileName = []
86
87  #
88  # Check for output file argument
89  #
90  if args.OutputFile <> None:
91    for Item in args.OutputFile:
92      #
93      # Save PEM filename and close output file
94      #
95      args.PemFileName.append(Item.name)
96      Item.close()
97
98      #
99      # Generate private key and save it to output file in a PEM file format
100      #
101      Process = subprocess.Popen('%s genrsa -out %s 2048' % (OpenSslCommand, Item.name), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
102      Process.communicate()
103      if Process.returncode <> 0:
104        print 'ERROR: RSA 2048 key generation failed'
105        sys.exit(Process.returncode)
106
107  #
108  # Check for input file argument
109  #
110  if args.InputFile <> None:
111    for Item in args.InputFile:
112      #
113      # Save PEM filename and close input file
114      #
115      args.PemFileName.append(Item.name)
116      Item.close()
117
118  PublicKeyHash = ''
119  for Item in args.PemFileName:
120    #
121    # Extract public key from private key into STDOUT
122    #
123    Process = subprocess.Popen('%s rsa -in %s -modulus -noout' % (OpenSslCommand, Item), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
124    PublicKeyHexString = Process.communicate()[0].split('=')[1].strip()
125    if Process.returncode <> 0:
126      print 'ERROR: Unable to extract public key from private key'
127      sys.exit(Process.returncode)
128    PublicKey = ''
129    for Index in range (0, len(PublicKeyHexString), 2):
130      PublicKey = PublicKey + chr(int(PublicKeyHexString[Index:Index + 2], 16))
131
132    #
133    # Generate SHA 256 hash of RSA 2048 bit public key into STDOUT
134    #
135    Process = subprocess.Popen('%s dgst -sha256 -binary' % (OpenSslCommand), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
136    Process.stdin.write (PublicKey)
137    PublicKeyHash = PublicKeyHash + Process.communicate()[0]
138    if Process.returncode <> 0:
139      print 'ERROR: Unable to extract SHA 256 hash of public key'
140      sys.exit(Process.returncode)
141
142  #
143  # Write SHA 256 hash of 2048 bit binary public key to public key hash file
144  #
145  try:
146    args.PublicKeyHashFile.write (PublicKeyHash)
147    args.PublicKeyHashFile.close ()
148  except:
149    pass
150
151  #
152  # Convert public key hash to a C structure string
153  #
154  PublicKeyHashC = '{'
155  for Item in PublicKeyHash:
156    PublicKeyHashC = PublicKeyHashC + '0x%02x, ' % (ord(Item))
157  PublicKeyHashC = PublicKeyHashC[:-2] + '}'
158
159  #
160  # Write SHA 256 of 2048 bit binary public key to public key hash C structure file
161  #
162  try:
163    args.PublicKeyHashCFile.write (PublicKeyHashC)
164    args.PublicKeyHashCFile.close ()
165  except:
166    pass
167
168  #
169  # If verbose is enabled display the public key in C structure format
170  #
171  if args.Verbose:
172    print 'PublicKeySha256 = ' + PublicKeyHashC
173