summaryrefslogtreecommitdiffstats
path: root/BaseTools/Source/Python/Rsa2048Sha256Sign/Rsa2048Sha256GenerateKeys.py
blob: 6c9b8c464e4db5643355a9c2e74ed4698750c7b3 (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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
## @file
# This tool can be used to generate new RSA 2048 bit private/public key pairs
# in a PEM file format using OpenSSL command line utilities that are installed
# on the path specified by the system environment variable OPENSSL_PATH.
# This tool can also optionally write one or more SHA 256 hashes of 2048 bit
# public keys to a binary file, write one or more SHA 256 hashes of 2048 bit
# public keys to a file in a C structure format, and in verbose mode display
# one or more SHA 256 hashes of 2048 bit public keys in a C structure format
# on STDOUT.
# This tool has been tested with OpenSSL 1.0.1e 11 Feb 2013
#
# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#

'''
Rsa2048Sha256GenerateKeys
'''
from __future__ import print_function

import os
import sys
import argparse
import subprocess
from Common.BuildVersion import gBUILD_VERSION

#
# Globals for help information
#
__prog__      = 'Rsa2048Sha256GenerateKeys'
__version__   = '%s Version %s' % (__prog__, '0.9 ' + gBUILD_VERSION)
__copyright__ = 'Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.'
__usage__     = '%s [options]' % (__prog__)


if __name__ == '__main__':
  #
  # Create command line argument parser object
  #
  parser = argparse.ArgumentParser(prog=__prog__, usage=__usage__, description=__copyright__, conflict_handler='resolve')
  group = parser.add_mutually_exclusive_group(required=True)
  group.add_argument("--version", action='version', version=__version__)
  group.add_argument("-o", "--output", dest='OutputFile', type=argparse.FileType('wb'), metavar='filename', nargs='*', help="specify the output private key filename in PEM format")
  group.add_argument("-i", "--input", dest='InputFile', type=argparse.FileType('rb'), metavar='filename', nargs='*', help="specify the input private key filename in PEM format")
  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")
  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")
  parser.add_argument("-v", "--verbose", dest='Verbose', action="store_true", help="increase output messages")
  parser.add_argument("-q", "--quiet", dest='Quiet', action="store_true", help="reduce output messages")
  parser.add_argument("--debug", dest='Debug', type=int, metavar='[0-9]', choices=range(0, 10), default=0, help="set debug level")

  #
  # Parse command line arguments
  #
  args = parser.parse_args()

  #
  # Generate file path to Open SSL command
  #
  OpenSslCommand = 'openssl'
  try:
    OpenSslPath = os.environ['OPENSSL_PATH']
    OpenSslCommand = os.path.join(OpenSslPath, OpenSslCommand)
    if ' ' in OpenSslCommand:
      OpenSslCommand = '"' + OpenSslCommand + '"'
  except:
    pass

  #
  # Verify that Open SSL command is available
  #
  try:
    Process = subprocess.Popen('%s version' % (OpenSslCommand), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  except:
    print('ERROR: Open SSL command not available.  Please verify PATH or set OPENSSL_PATH')
    sys.exit(1)

  Version = Process.communicate()
  if Process.returncode != 0:
    print('ERROR: Open SSL command not available.  Please verify PATH or set OPENSSL_PATH')
    sys.exit(Process.returncode)
  print(Version[0].decode())

  args.PemFileName = []

  #
  # Check for output file argument
  #
  if args.OutputFile is not None:
    for Item in args.OutputFile:
      #
      # Save PEM filename and close output file
      #
      args.PemFileName.append(Item.name)
      Item.close()

      #
      # Generate private key and save it to output file in a PEM file format
      #
      Process = subprocess.Popen('%s genrsa -out %s 2048' % (OpenSslCommand, Item.name), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
      Process.communicate()
      if Process.returncode != 0:
        print('ERROR: RSA 2048 key generation failed')
        sys.exit(Process.returncode)

  #
  # Check for input file argument
  #
  if args.InputFile is not None:
    for Item in args.InputFile:
      #
      # Save PEM filename and close input file
      #
      args.PemFileName.append(Item.name)
      Item.close()

  PublicKeyHash = bytearray()
  for Item in args.PemFileName:
    #
    # Extract public key from private key into STDOUT
    #
    Process = subprocess.Popen('%s rsa -in %s -modulus -noout' % (OpenSslCommand, Item), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
    PublicKeyHexString = Process.communicate()[0].decode().split(b'=')[1].strip()
    if Process.returncode != 0:
      print('ERROR: Unable to extract public key from private key')
      sys.exit(Process.returncode)
    PublicKey = bytearray()
    for Index in range (0, len(PublicKeyHexString), 2):
      PublicKey = PublicKey + PublicKeyHexString[Index:Index + 2]

    #
    # Generate SHA 256 hash of RSA 2048 bit public key into STDOUT
    #
    Process = subprocess.Popen('%s dgst -sha256 -binary' % (OpenSslCommand), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
    Process.stdin.write (PublicKey)
    PublicKeyHash = PublicKeyHash + Process.communicate()[0].decode()
    if Process.returncode != 0:
      print('ERROR: Unable to extract SHA 256 hash of public key')
      sys.exit(Process.returncode)

  #
  # Write SHA 256 hash of 2048 bit binary public key to public key hash file
  #
  try:
    args.PublicKeyHashFile.write (PublicKeyHash)
    args.PublicKeyHashFile.close ()
  except:
    pass

  #
  # Convert public key hash to a C structure string
  #
  PublicKeyHashC = '{'
  for Item in PublicKeyHash:
    PublicKeyHashC = PublicKeyHashC + '0x%02x, ' % (Item)
  PublicKeyHashC = PublicKeyHashC[:-2] + '}'

  #
  # Write SHA 256 of 2048 bit binary public key to public key hash C structure file
  #
  try:
    args.PublicKeyHashCFile.write (bytes(PublicKeyHashC))
    args.PublicKeyHashCFile.close ()
  except:
    pass

  #
  # If verbose is enabled display the public key in C structure format
  #
  if args.Verbose:
    print('PublicKeySha256 = ' + PublicKeyHashC)