/ 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