| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- # Copyright 2016 Google Inc. All Rights Reserved.
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- """Implement the U2F variant of ISO 7816 extended APDU.
- This module implements a subset ISO 7816 APDU encoding. In particular,
- it only supports extended length encoding, it only supports commands
- that expect a reply, and it does not support explicitly specifying
- the length of the expected reply.
- It also implements the U2F variant of ISO 7816 where the Lc field
- is always specified, even if there is no data.
- """
- import struct
- from pyu2f import errors
- CMD_REGISTER = 0x01
- CMD_AUTH = 0x02
- CMD_VERSION = 0x03
- class CommandApdu(object):
- """Represents a Command APDU.
- Represents a Command APDU sent to the security key. Encoding
- is specified in FIDO U2F standards.
- """
- cla = None
- ins = None
- p1 = None
- p2 = None
- data = None
- def __init__(self, cla, ins, p1, p2, data=None):
- self.cla = cla
- self.ins = ins
- self.p1 = p1
- self.p2 = p2
- if data and len(data) > 65535:
- raise errors.InvalidCommandError()
- if data:
- self.data = data
- def ToByteArray(self):
- """Serialize the command.
- Encodes the command as per the U2F specs, using the standard
- ISO 7816-4 extended encoding. All Commands expect data, so
- Le is always present.
- Returns:
- Python bytearray of the encoded command.
- """
- lc = self.InternalEncodeLc()
- out = bytearray(4) # will extend
- out[0] = self.cla
- out[1] = self.ins
- out[2] = self.p1
- out[3] = self.p2
- if self.data:
- out.extend(lc)
- out.extend(self.data)
- out.extend([0x00, 0x00]) # Le
- else:
- out.extend([0x00, 0x00, 0x00]) # Le
- return out
- def ToLegacyU2FByteArray(self):
- """Serialize the command in the legacy format.
- Encodes the command as per the U2F specs, using the legacy
- encoding in which LC is always present.
- Returns:
- Python bytearray of the encoded command.
- """
- lc = self.InternalEncodeLc()
- out = bytearray(4) # will extend
- out[0] = self.cla
- out[1] = self.ins
- out[2] = self.p1
- out[3] = self.p2
- out.extend(lc)
- if self.data:
- out.extend(self.data)
- out.extend([0x00, 0x00]) # Le
- return out
- def InternalEncodeLc(self):
- dl = 0
- if self.data:
- dl = len(self.data)
- # The top two bytes are guaranteed to be 0 by the assertion
- # in the constructor.
- fourbyte = struct.pack('>I', dl)
- return bytearray(fourbyte[1:])
- class ResponseApdu(object):
- """Represents a Response APDU.
- Represents a Response APU sent by the security key. Encoding
- is specified in FIDO U2F standards.
- """
- body = None
- sw1 = None
- sw2 = None
- def __init__(self, data):
- self.dbg_full_packet = data
- if not data or len(data) < 2:
- raise errors.InvalidResponseError()
- if len(data) > 2:
- self.body = data[:-2]
- self.sw1 = data[-2]
- self.sw2 = data[-1]
- def IsSuccess(self):
- return self.sw1 == 0x90 and self.sw2 == 0x00
- def CheckSuccessOrRaise(self):
- if self.sw1 == 0x69 and self.sw2 == 0x85:
- raise errors.TUPRequiredError()
- elif self.sw1 == 0x6a and self.sw2 == 0x80:
- raise errors.InvalidKeyHandleError()
- elif self.sw1 == 0x69 and self.sw2 == 0x84:
- raise errors.InvalidKeyHandleError()
- elif not self.IsSuccess():
- raise errors.ApduError(self.sw1, self.sw2)
|