diff --git a/.gitignore b/.gitignore index 78d47ef..899a641 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea *.iml *.swp +*.swo diff --git a/commands/constructors.go b/commands/constructors.go index 0f3c238..dbfdaac 100644 --- a/commands/constructors.go +++ b/commands/constructors.go @@ -248,3 +248,45 @@ func CreateGetPseudoRandomCommand(numBytes uint16) *CommandMessage { return command } + +func CreatePutWrapkeyCommand(objID uint16, label []byte, domains uint16, capabilities uint64, algorithm Algorithm, delegated uint64, wrapkey []byte) (*CommandMessage, error) { + if len(label) > LabelLength { + return nil, errors.New("label is too long") + } + if len(label) < LabelLength { + label = append(label, bytes.Repeat([]byte{0x00}, LabelLength-len(label))...) + } + switch algorithm { + case AlgorithmAES128CCMWrap: + if keyLen := len(wrapkey); keyLen != 16 { + return nil, errors.New("wrapkey is wrong length") + } + case AlgorithmAES192CCMWrap: + if keyLen := len(wrapkey); keyLen != 24 { + return nil, errors.New("wrapkey is wrong length") + } + case AlgorithmAES256CCMWrap: + if keyLen := len(wrapkey); keyLen != 32 { + return nil, errors.New("wrapkey is wrong length") + } + default: + return nil, errors.New("invalid algorithm") + } + + command := &CommandMessage{ + CommandType: CommandTypePutWrapKey, + } + + payload := bytes.NewBuffer([]byte{}) + binary.Write(payload, binary.BigEndian, objID) + payload.Write(label) + binary.Write(payload, binary.BigEndian, domains) + binary.Write(payload, binary.BigEndian, capabilities) + binary.Write(payload, binary.BigEndian, algorithm) + binary.Write(payload, binary.BigEndian, delegated) + payload.Write(wrapkey) + + command.Data = payload.Bytes() + + return command, nil +} diff --git a/commands/response.go b/commands/response.go index 276f031..d107205 100644 --- a/commands/response.go +++ b/commands/response.go @@ -83,6 +83,10 @@ type ( ChangeAuthenticationKeyResponse struct { ObjectID uint16 } + + PutWrapkeyResponse struct { + ObjectID uint16 + } ) // ParseResponse parses the binary response from the card to the relevant Response type. @@ -139,6 +143,8 @@ func ParseResponse(data []byte) (Response, error) { return parseChangeAuthenticationKeyResponse(payload) case CommandTypeGetPseudoRandom: return parseGetPseudoRandomResponse(payload), nil + case CommandTypePutWrapKey: + return parsePutWrapkeyResponse(payload) case ErrorResponseCode: return nil, parseErrorResponse(payload) default: @@ -288,6 +294,19 @@ func parseGetPseudoRandomResponse(payload []byte) Response { return payload } +func parsePutWrapkeyResponse(payload []byte) (Response, error) { + if len(payload) != 2 { + return nil, errors.New("invalid response payload length") + } + + var objectID uint16 + err := binary.Read(bytes.NewReader(payload), binary.BigEndian, &objectID) + if err != nil { + return nil, err + } + return &PutWrapkeyResponse{ObjectID: objectID}, nil +} + // Error formats a card error message into a human readable format func (e *Error) Error() string { message := "" diff --git a/commands/types.go b/commands/types.go index 9194da1..7812a70 100644 --- a/commands/types.go +++ b/commands/types.go @@ -84,6 +84,9 @@ const ( AlgorithmSecp256k1 Algorithm = 15 AlgorithmYubicoAESAuthentication Algorithm = 38 AlgorighmED25519 Algorithm = 46 + AlgorithmAES128CCMWrap Algorithm = 29 + AlgorithmAES192CCMWrap Algorithm = 41 + AlgorithmAES256CCMWrap Algorithm = 42 // Capabilities CapabilityGetOpaque uint64 = 0x0000000000000001