xref: /aosp_15_r20/external/autotest/client/cros/certificate_util.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Lint as: python2, python3
2*9c5db199SXin Li# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
4*9c5db199SXin Li# found in the LICENSE file.
5*9c5db199SXin Li
6*9c5db199SXin Liimport tempfile
7*9c5db199SXin Li
8*9c5db199SXin Lifrom autotest_lib.client.bin import utils
9*9c5db199SXin Li
10*9c5db199SXin Liclass PEMCertificate(object):
11*9c5db199SXin Li    """Object enclosing a PEM certificate.
12*9c5db199SXin Li
13*9c5db199SXin Li    Uses the "openssl" utility to report various properties of a certificate.
14*9c5db199SXin Li
15*9c5db199SXin Li    """
16*9c5db199SXin Li    OPENSSL_COMMAND = 'openssl'
17*9c5db199SXin Li    ATTRIBUTE_SUBJECT = 'subject'
18*9c5db199SXin Li    ATTRIBUTE_FINGERPRINT = 'fingerprint'
19*9c5db199SXin Li
20*9c5db199SXin Li    def __init__(self, pem_contents):
21*9c5db199SXin Li        self._pem_contents = pem_contents
22*9c5db199SXin Li        self._fingerprint = None
23*9c5db199SXin Li        self._subject = None
24*9c5db199SXin Li        self._subject_dict = None
25*9c5db199SXin Li
26*9c5db199SXin Li
27*9c5db199SXin Li    def get_attribute(self, attribute):
28*9c5db199SXin Li        """Returns the named attribute of the certificate.
29*9c5db199SXin Li
30*9c5db199SXin Li        @param attribute string referring to the attribute to retrieve.
31*9c5db199SXin Li        @return string containing the retrieved attribute value.
32*9c5db199SXin Li
33*9c5db199SXin Li        """
34*9c5db199SXin Li        with tempfile.NamedTemporaryFile() as temp:
35*9c5db199SXin Li            temp.write(self._pem_contents)
36*9c5db199SXin Li            temp.flush()
37*9c5db199SXin Li            output = utils.system_output(
38*9c5db199SXin Li                '%s x509 -noout -nameopt compat -%s -in %s' %
39*9c5db199SXin Li                (self.OPENSSL_COMMAND, attribute, temp.name))
40*9c5db199SXin Li        # Output is of the form "name=value..."
41*9c5db199SXin Li        return output.split('=', 1)[1]
42*9c5db199SXin Li
43*9c5db199SXin Li
44*9c5db199SXin Li    @property
45*9c5db199SXin Li    def fingerprint(self):
46*9c5db199SXin Li        """Returns the SHA-1 fingerprint of a certificate."""
47*9c5db199SXin Li        if self._fingerprint is None:
48*9c5db199SXin Li            self._fingerprint = self.get_attribute(self.ATTRIBUTE_FINGERPRINT)
49*9c5db199SXin Li        return self._fingerprint
50*9c5db199SXin Li
51*9c5db199SXin Li
52*9c5db199SXin Li    @property
53*9c5db199SXin Li    def subject(self):
54*9c5db199SXin Li        """Returns the subject DN of the certificate as a list of name=value"""
55*9c5db199SXin Li        if self._subject is None:
56*9c5db199SXin Li            subject = self.get_attribute(self.ATTRIBUTE_SUBJECT)
57*9c5db199SXin Li            # OpenSSL returns a form of:
58*9c5db199SXin Li            #   " /C=US/ST=CA/L=Mountain View/CN=chromelab..."
59*9c5db199SXin Li            # but we want to return something like:
60*9c5db199SXin Li            #   [ "C=US", "ST=CA", "L=Mountain View", "CN=chromelab..." ]
61*9c5db199SXin Li            self._subject = subject.lstrip(' /').split('/')
62*9c5db199SXin Li        return self._subject
63*9c5db199SXin Li
64*9c5db199SXin Li
65*9c5db199SXin Li    @property
66*9c5db199SXin Li    def subject_dict(self):
67*9c5db199SXin Li        """Returns the subject DN of the certificate as a dict of name:value"""
68*9c5db199SXin Li        if self._subject_dict is None:
69*9c5db199SXin Li          # Convert the list [ 'A=B', ... ] into a dict { 'A': 'B',  ... }
70*9c5db199SXin Li          self._subject_dict = dict([x.split('=', 1) for x in self.subject])
71*9c5db199SXin Li        return self._subject_dict
72