/ adafruit_atecc / adafruit_atecc_asn1.py
adafruit_atecc_asn1.py
  1  # Copyright (c) 2018 Arduino SA. All rights reserved.
  2  #
  3  # This library is free software; you can redistribute it and/or
  4  # modify it under the terms of the GNU Lesser General Public
  5  # License as published by the Free Software Foundation; either
  6  # version 2.1 of the License, or (at your option) any later version.
  7  #
  8  # This library is distributed in the hope that it will be useful,
  9  # but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 11  # Lesser General Public License for more details.
 12  #
 13  # You should have received a copy of the GNU Lesser General Public
 14  # License along with this library; if not, write to the Free Software
 15  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 16  #
 17  # The MIT License (MIT)
 18  #
 19  # Copyright (c) 2019 Brent Rubell for Adafruit Industries
 20  #
 21  # Permission is hereby granted, free of charge, to any person obtaining a copy
 22  # of this software and associated documentation files (the "Software"), to deal
 23  # in the Software without restriction, including without limitation the rights
 24  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 25  # copies of the Software, and to permit persons to whom the Software is
 26  # furnished to do so, subject to the following conditions:
 27  #
 28  # The above copyright notice and this permission notice shall be included in
 29  # all copies or substantial portions of the Software.
 30  #
 31  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 32  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 33  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 34  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 35  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 36  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 37  # THE SOFTWARE.
 38  """
 39  `atecc_asn1`
 40  ================================================================================
 41  
 42  ASN.1 Utilities for the Adafruit_ATECC Module.
 43  
 44  * Author(s): Brent Rubell
 45  
 46  Implementation Notes
 47  --------------------
 48  
 49  **Software and Dependencies:**
 50  
 51  * Adafruit CircuitPython firmware for the supported boards:
 52    https://github.com/adafruit/circuitpython/releases
 53  """
 54  import struct
 55  
 56  # pylint: disable=invalid-name
 57  def get_signature(signature, data):
 58      """Appends signature data to buffer."""
 59      # Signature algorithm
 60      data += b"\x30\x0a\x06\x08"
 61      # ECDSA with SHA256
 62      data += b"\x2a\x86\x48\xce\x3d\x04\x03\x02"
 63      r = signature[0]
 64      s = signature[32]
 65      r_len = 32
 66      s_len = 32
 67  
 68      while r == 0x00 and r_len > 1:
 69          r += 1
 70          r_len -= 1
 71  
 72      while s == 0x00 and s_len > 1:
 73          s += 1
 74          s_len -= 1
 75  
 76      if r & 0x80:
 77          r_len += 1
 78  
 79      if s & 0x80:
 80          s_len += 1
 81  
 82      data += b"\x03" + struct.pack("B", r_len + s_len + 7) + b"\x00"
 83  
 84      data += b"\x30" + struct.pack("B", r_len + s_len + 4)
 85  
 86      data += b"\x02" + struct.pack("B", r_len)
 87  
 88      if r & 0x80:
 89          data += b"\x00"
 90          r_len -= 1
 91      data += signature[0:r_len]
 92  
 93      if r & 0x80:
 94          r_len += 1
 95  
 96      data += b"\x02" + struct.pack("B", s_len)
 97      if s & 0x80:
 98          data += b"\x00"
 99          s_len -= 1
100  
101      data += signature[s_len:]
102  
103      if s & 0x80:
104          s_len += 1
105  
106      return 21 + r_len + s_len
107  
108  
109  # pylint: disable=too-many-arguments
110  def get_issuer_or_subject(data, country, state_prov, locality, org, org_unit, common):
111      """Appends issuer or subject, if they exist, to data."""
112      if country:
113          get_name(country, 0x06, data)
114      if state_prov:
115          get_name(state_prov, 0x08, data)
116      if locality:
117          get_name(locality, 0x07, data)
118      if org:
119          get_name(org, 0x0A, data)
120      if org_unit:
121          get_name(org_unit, 0x0B, data)
122      if common:
123          get_name(common, 0x03, data)
124  
125  
126  def get_name(name, obj_type, data):
127      """Appends ASN.1 string in form: set -> seq -> objid -> string
128      :param str name: String to append to buffer.
129      :param int obj_type: Object identifier type.
130      :param bytearray data: Buffer to write to.
131      """
132      # ASN.1 SET
133      data += b"\x31" + struct.pack("B", len(name) + 9)
134      # ASN.1 SEQUENCE
135      data += b"\x30" + struct.pack("B", len(name) + 7)
136      # ASN.1 OBJECT IDENTIFIER
137      data += b"\x06\x03\x55\x04" + struct.pack("B", obj_type)
138  
139      # ASN.1 PRINTABLE STRING
140      data += b"\x13" + struct.pack("B", len(name))
141      data.extend(name)
142      return len(name) + 11
143  
144  
145  def get_version(data):
146      """Appends X.509 version to data."""
147      #  If no extensions are present, but a UniqueIdentifier
148      #  is present, the version SHOULD be 2 (value is 1) [4-1-2]
149      data += b"\x02\x01\x00"
150  
151  
152  def get_sequence_header(length, data):
153      """Appends sequence header to provided data."""
154      data += b"\x30"
155      if length > 255:
156          data += b"\x82"
157          data.append((length >> 8) & 0xFF)
158      elif length > 127:
159          data += b"\x81"
160      length_byte = struct.pack("B", (length) & 0xFF)
161      data += length_byte
162  
163  
164  def get_public_key(data, public_key):
165      """Appends public key subject and object identifiers."""
166      # Subject: Public Key
167      data += b"\x30" + struct.pack("B", (0x59) & 0xFF) + b"\x30\x13"
168      # Object identifier: EC Public Key
169      data += b"\x06\x07\x2a\x86\x48\xce\x3d\x02\x01"
170      # Object identifier: PRIME 256 v1
171      data += b"\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04"
172      # Extend the buffer by the public key
173      data += public_key
174  
175  
176  def get_signature_length(signature):
177      """Return length of ECDSA signature.
178      :param bytearray signature: Signed SHA256 hash.
179      """
180      r = signature[0]
181      s = signature[32]
182      r_len = 32
183      s_len = 32
184  
185      while r == 0x00 and r_len > 1:
186          r += 1
187          r_len -= 1
188  
189      if r & 0x80:
190          r_len += 1
191  
192      while s == 0x00 and s_len > 1:
193          s += 1
194          s_len -= 1
195  
196      if s & 0x80:
197          s_len += 1
198      return 21 + r_len + s_len
199  
200  
201  def get_sequence_header_length(seq_header_len):
202      """Returns length of SEQUENCE header."""
203      if seq_header_len > 255:
204          return 4
205      if seq_header_len > 127:
206          return 3
207      return 2
208  
209  
210  def issuer_or_subject_length(country, state_prov, city, org, org_unit, common):
211      """Returns total length of provided certificate information."""
212      tot_len = 0
213      if country:
214          tot_len += 11 + len(country)
215      if state_prov:
216          tot_len += 11 + len(state_prov)
217      if city:
218          tot_len += 11 + len(city)
219      if org:
220          tot_len += 11 + len(org)
221      if org_unit:
222          tot_len += 11 + len(org_unit)
223      if common:
224          tot_len += 11 + len(common)
225      else:
226          raise TypeError("Provided length must be > 0")
227      return tot_len