diff --git a/commands/constructors.go b/commands/constructors.go index dbfdaac..d4e7576 100644 --- a/commands/constructors.go +++ b/commands/constructors.go @@ -290,3 +290,39 @@ func CreatePutWrapkeyCommand(objID uint16, label []byte, domains uint16, capabil return command, nil } + +func CreatePutAuthkeyCommand(objID uint16, label []byte, domains uint16, capabilities, delegated uint64, encKey, macKey []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))...) + } + algorithm := AlgorithmYubicoAESAuthentication + // TODO: support P256 Authentication when it is released + // https://github.com/Yubico/yubihsm-shell/blob/1c8e254603e72f3f39cf1c3910996dbfcdba2b12/lib/yubihsm.c#L3110 + if len(encKey) != 16 { + return nil, errors.New("invalid encryption key length") + } + if len(macKey) != 16 { + return nil, errors.New("invalid mac key length") + } + + command := &CommandMessage{ + CommandType: CommandTypePutAuthKey, + } + + 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(encKey) + payload.Write(macKey) + + command.Data = payload.Bytes() + + return command, nil +} diff --git a/commands/response.go b/commands/response.go index d107205..2ae790c 100644 --- a/commands/response.go +++ b/commands/response.go @@ -87,6 +87,10 @@ type ( PutWrapkeyResponse struct { ObjectID uint16 } + + PutAuthkeyResponse struct { + ObjectID uint16 + } ) // ParseResponse parses the binary response from the card to the relevant Response type. @@ -145,6 +149,8 @@ func ParseResponse(data []byte) (Response, error) { return parseGetPseudoRandomResponse(payload), nil case CommandTypePutWrapKey: return parsePutWrapkeyResponse(payload) + case CommandTypePutAuthKey: + return parsePutAuthkeyResponse(payload) case ErrorResponseCode: return nil, parseErrorResponse(payload) default: @@ -307,6 +313,19 @@ func parsePutWrapkeyResponse(payload []byte) (Response, error) { return &PutWrapkeyResponse{ObjectID: objectID}, nil } +func parsePutAuthkeyResponse(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 &PutAuthkeyResponse{ObjectID: objectID}, nil +} + // Error formats a card error message into a human readable format func (e *Error) Error() string { message := ""