diff --git a/commands/constructors.go b/commands/constructors.go index 4ffccfd..c303b06 100644 --- a/commands/constructors.go +++ b/commands/constructors.go @@ -411,7 +411,41 @@ func CreateSignAttestationCertCommand(keyObjID, attestationObjID uint16) (*Comma payload := bytes.NewBuffer([]byte{}) binary.Write(payload, binary.BigEndian, keyObjID) binary.Write(payload, binary.BigEndian, attestationObjID) - + command.Data = payload.Bytes() + + return command, nil +} + +func CreateExportWrappedCommand(wrapObjID uint16, objType uint8, objID uint16) (*CommandMessage, error) { + command := &CommandMessage{ + CommandType: CommandTypeExportWrapped, + } + + payload := bytes.NewBuffer([]byte{}) + binary.Write(payload, binary.BigEndian, wrapObjID) + binary.Write(payload, binary.BigEndian, objType) + binary.Write(payload, binary.BigEndian, objID) + command.Data = payload.Bytes() + + return command, nil +} + +// CreateImportWrappedCommand will import a wrapped/encrypted Object that was +// previously exported by an YubiHSM2 device. The imported object will retain +// its metadata (Object ID, Domains, Capabilities …etc), however, the object’s +// origin will be marked as imported instead of generated. +func CreateImportWrappedCommand(wrapObjID uint16, nonce, data []byte) (*CommandMessage, error) { + command := &CommandMessage{ + CommandType: CommandTypeImportWrapped, + } + if len(nonce) != 13 { + return nil, errors.New("invalid nonce length") + } + + payload := bytes.NewBuffer([]byte{}) + binary.Write(payload, binary.BigEndian, wrapObjID) + payload.Write(nonce) + payload.Write(data) command.Data = payload.Bytes() return command, nil diff --git a/commands/response.go b/commands/response.go index c2f6c60..bd34727 100644 --- a/commands/response.go +++ b/commands/response.go @@ -107,6 +107,16 @@ type ( SignAttestationCertResponse struct { Cert []byte } + + ExportWrappedResponse struct { + Nonce []byte + Data []byte + } + + ImportWrappedResponse struct { + ObjectType uint8 + ObjectID uint16 + } ) // ParseResponse parses the binary response from the card to the relevant Response type. @@ -175,6 +185,10 @@ func ParseResponse(data []byte) (Response, error) { return parseGetOpaqueResponse(payload) case CommandTypeAttestAsymmetric: return parseAttestationCertResponse(payload) + case CommandTypeExportWrapped: + return parseExportWrappedResponse(payload) + case CommandTypeImportWrapped: + return parseImportWrappedResponse(payload) case ErrorResponseCode: return nil, parseErrorResponse(payload) default: @@ -397,6 +411,34 @@ func parseAttestationCertResponse(payload []byte) (Response, error) { }, nil } +func parseExportWrappedResponse(payload []byte) (Response, error) { + if len(payload) < 13 { + return nil, errors.New("invalid response payload length") + } + + return &ExportWrappedResponse{ + Nonce: payload[:13], + Data: payload[13:], + }, nil +} + +func parseImportWrappedResponse(payload []byte) (Response, error) { + if len(payload) != 3 { + return nil, errors.New("invalid response payload length") + } + + var objID uint16 + err := binary.Read(bytes.NewReader(payload[1:3]), binary.BigEndian, &objID) + if err != nil { + return nil, err + } + + return &ImportWrappedResponse{ + ObjectType: uint8(payload[0]), + ObjectID: objID, + }, nil +} + // Error formats a card error message into a human readable format func (e *Error) Error() string { message := ""