Bug 1928997: Update tabs icon in Unified Search popup r=desktop-theme-reviewers,daleh...
[gecko.git] / security / manager / tools / pypkcs12.py
blobab4c42d53c6f6a5e8f9c53f4387aac957d55a677
1 #!/usr/bin/env python
3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 """
8 Reads a specification from stdin or a file and outputs a PKCS12
9 file with the desired properties.
11 The input format currently consists of a pycert certificate
12 specification (see pycert.py).
13 Currently, keys other than the default key are not supported.
14 The password that is used to encrypt and authenticate the file
15 is "password".
16 """
18 import base64
19 import os
20 import shutil
21 import subprocess
22 import sys
24 import mozinfo
25 import pycert
26 import pykey
27 import six
28 from mozfile import NamedTemporaryFile
31 class Error(Exception):
32 """Base class for exceptions in this module."""
34 pass
37 class OpenSSLError(Error):
38 """Class for handling errors when calling OpenSSL."""
40 def __init__(self, status):
41 super(OpenSSLError, self).__init__()
42 self.status = status
44 def __str__(self):
45 return "Error running openssl: %s " % self.status
48 def runUtil(util, args):
49 env = os.environ.copy()
50 if mozinfo.os == "linux":
51 pathvar = "LD_LIBRARY_PATH"
52 app_path = os.path.dirname(util)
53 if pathvar in env:
54 env[pathvar] = "%s%s%s" % (app_path, os.pathsep, env[pathvar])
55 else:
56 env[pathvar] = app_path
57 proc = subprocess.run(
58 [util] + args,
59 env=env,
60 universal_newlines=True,
62 return proc.returncode
65 class PKCS12(object):
66 """Utility class for reading a specification and generating
67 a PKCS12 file"""
69 def __init__(self, paramStream):
70 self.cert = pycert.Certificate(paramStream)
71 self.key = pykey.keyFromSpecification("default")
73 def toDER(self):
74 with NamedTemporaryFile(mode="wt+") as certTmp, NamedTemporaryFile(
75 mode="wt+"
76 ) as keyTmp, NamedTemporaryFile(mode="rb+") as pkcs12Tmp:
77 certTmp.write(self.cert.toPEM())
78 certTmp.flush()
79 keyTmp.write(self.key.toPEM())
80 keyTmp.flush()
81 openssl = shutil.which("openssl")
82 status = runUtil(
83 openssl,
85 "pkcs12",
86 "-export",
87 "-inkey",
88 keyTmp.name,
89 "-in",
90 certTmp.name,
91 "-out",
92 pkcs12Tmp.name,
93 "-passout",
94 "pass:password",
97 if status != 0:
98 raise OpenSSLError(status)
99 return pkcs12Tmp.read()
101 def toPEM(self):
102 output = "-----BEGIN PKCS12-----"
103 der = self.toDER()
104 b64 = six.ensure_text(base64.b64encode(der))
105 while b64:
106 output += "\n" + b64[:64]
107 b64 = b64[64:]
108 output += "\n-----END PKCS12-----"
109 return output
112 # The build harness will call this function with an output
113 # file-like object and a path to a file containing a
114 # specification. This will read the specification and output
115 # the PKCS12 file.
116 def main(output, inputPath):
117 with open(inputPath) as configStream:
118 output.write(PKCS12(configStream).toDER())
121 # When run as a standalone program, this will read a specification from
122 # stdin and output the PKCS12 file as PEM to stdout.
123 if __name__ == "__main__":
124 print(PKCS12(sys.stdin).toPEM())