diff --git a/commands/constructors.go b/commands/constructors.go index 12fc1e3..74e9153 100644 --- a/commands/constructors.go +++ b/commands/constructors.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "errors" + "io" ) func CreateCreateSessionCommand(keySetID uint16, hostChallenge []byte) (*CommandMessage, error) { @@ -77,6 +78,20 @@ func CreateSignDataEddsaCommand(keyID uint16, data []byte) (*CommandMessage, err return command, nil } +func CreateSignDataEcdsaCommand(keyID uint16, data []byte) (*CommandMessage, error) { + command := &CommandMessage{ + CommandType: CommandTypeSignDataEcdsa, + } + + payload := bytes.NewBuffer([]byte{}) + binary.Write(payload, binary.BigEndian, keyID) + payload.Write(data) + + command.Data = payload.Bytes() + + return command, nil +} + func CreatePutAsymmetricKeyCommand(keyID uint16, label []byte, domains uint16, capabilities uint64, algorithm Algorithm, keyPart1 []byte, keyPart2 []byte) (*CommandMessage, error) { if len(label) > LabelLength { return nil, errors.New("label is too long") @@ -104,6 +119,51 @@ func CreatePutAsymmetricKeyCommand(keyID uint16, label []byte, domains uint16, c return command, nil } +type ListCommandOption func(w io.Writer) + +func NewObjectTypeOption(objectType uint8) ListCommandOption { + return func(w io.Writer) { + binary.Write(w, binary.BigEndian, ListObjectParamType) + binary.Write(w, binary.BigEndian, objectType) + } +} + +func NewIDOption(id uint16) ListCommandOption { + return func(w io.Writer) { + binary.Write(w, binary.BigEndian, ListObjectParamID) + binary.Write(w, binary.BigEndian, id) + } +} + +func CreateListObjectsCommand(options ...ListCommandOption) (*CommandMessage, error) { + command := &CommandMessage{ + CommandType: CommandTypeListObjects, + } + + payload := bytes.NewBuffer([]byte{}) + for _, opt := range options { + opt(payload) + } + + command.Data = payload.Bytes() + + return command, nil +} + +func CreateGetObjectInfoCommand(keyID uint16, objectType uint8) (*CommandMessage, error) { + command := &CommandMessage{ + CommandType: CommandTypeGetObjectInfo, + } + + payload := bytes.NewBuffer([]byte{}) + binary.Write(payload, binary.BigEndian, keyID) + binary.Write(payload, binary.BigEndian, objectType) + + command.Data = payload.Bytes() + + return command, nil +} + func CreateCloseSessionCommand() (*CommandMessage, error) { command := &CommandMessage{ CommandType: CommandTypeCloseSession, @@ -124,6 +184,19 @@ func CreateGetPubKeyCommand(keyID uint16) (*CommandMessage, error) { return command, nil } +func CreateDeleteObjectCommand(objID uint16, objType uint8) (*CommandMessage, error) { + command := &CommandMessage{ + CommandType: CommandTypeDeleteObject, + } + + payload := bytes.NewBuffer([]byte{}) + binary.Write(payload, binary.BigEndian, objID) + binary.Write(payload, binary.BigEndian, objType) + command.Data = payload.Bytes() + + return command, nil +} + func CreateEchoCommand(data []byte) (*CommandMessage, error) { command := &CommandMessage{ CommandType: CommandTypeEcho, diff --git a/commands/response.go b/commands/response.go index 5503c72..1597efd 100644 --- a/commands/response.go +++ b/commands/response.go @@ -35,10 +35,37 @@ type ( KeyID uint16 } + ObjectInfoResponse struct { + Capabilities uint64 + ObjectID uint16 + Length uint16 + Domains uint16 + Type uint8 + Algorithm Algorithm + Sequence uint8 + Origin uint8 + Label [40]byte + DelegatedCapabilites uint64 + } + + Object struct { + ObjectID uint16 + ObjectType uint8 + Sequence uint8 + } + + ListObjectsResponse struct { + Objects []Object + } + SignDataEddsaResponse struct { Signature []byte } + SignDataEcdsaResponse struct { + Signature []byte + } + GetPubKeyResponse struct { Algorithm Algorithm // KeyData can contain different formats depending on the algorithm according to the YubiHSM2 documentation. @@ -82,12 +109,20 @@ func ParseResponse(data []byte) (Response, error) { return parseCreateAsymmetricKeyResponse(payload) case CommandTypeSignDataEddsa: return parseSignDataEddsaResponse(payload) + case CommandTypeSignDataEcdsa: + return parseSignDataEcdsaResponse(payload) case CommandTypePutAsymmetric: return parsePutAsymmetricKeyResponse(payload) + case CommandTypeListObjects: + return parseListObjectsResponse(payload) + case CommandTypeGetObjectInfo: + return parseGetObjectInfoResponse(payload) case CommandTypeCloseSession: return nil, nil case CommandTypeGetPubKey: return parseGetPubKeyResponse(payload) + case CommandTypeDeleteObject: + return nil, nil case CommandTypeEcho: return parseEchoResponse(payload) case ErrorResponseCode: @@ -149,6 +184,12 @@ func parseSignDataEddsaResponse(payload []byte) (Response, error) { }, nil } +func parseSignDataEcdsaResponse(payload []byte) (Response, error) { + return &SignDataEcdsaResponse{ + Signature: payload, + }, nil +} + func parsePutAsymmetricKeyResponse(payload []byte) (Response, error) { if len(payload) != 2 { return nil, errors.New("invalid response payload length") @@ -165,6 +206,34 @@ func parsePutAsymmetricKeyResponse(payload []byte) (Response, error) { }, nil } +func parseListObjectsResponse(payload []byte) (Response, error) { + if len(payload)%4 != 0 { + return nil, errors.New("invalid response payload length") + } + + response := ListObjectsResponse{ + Objects: make([]Object, len(payload)/4), + } + + err := binary.Read(bytes.NewReader(payload), binary.BigEndian, &response.Objects) + if err != nil { + return nil, err + } + + return &response, nil +} + +func parseGetObjectInfoResponse(payload []byte) (Response, error) { + response := ObjectInfoResponse{} + + err := binary.Read(bytes.NewReader(payload), binary.BigEndian, &response) + if err != nil { + return nil, err + } + + return &response, nil +} + func parseGetPubKeyResponse(payload []byte) (Response, error) { if len(payload) < 1 { return nil, errors.New("invalid response payload length") diff --git a/commands/types.go b/commands/types.go index 683a353..830d42f 100644 --- a/commands/types.go +++ b/commands/types.go @@ -78,7 +78,9 @@ const ( ErrorCodeCommandUnexecuted ErrorCode = 0xff // Algorithms - AlgorighmED25519 Algorithm = 46 + AlgorithmP256 Algorithm = 12 + AlgorithmSecp256k1 Algorithm = 15 + AlgorighmED25519 Algorithm = 46 // Capabilities CapabilityGetOpaque uint64 = 0x0000000000000001 @@ -145,4 +147,17 @@ const ( Domain14 uint16 = 0x2000 Domain15 uint16 = 0x4000 Domain16 uint16 = 0x8000 + + // object types + ObjectTypeOpaque uint8 = 0x01 + ObjectTypeAuthenticationKey uint8 = 0x02 + ObjectTypeAsymmetricKey uint8 = 0x03 + ObjectTypeWrapKey uint8 = 0x04 + ObjectTypeHmacKey uint8 = 0x05 + ObjectTypeTemplate uint8 = 0x06 + ObjectTypeOtpAeadKey uint8 = 0x07 + + // list objects params + ListObjectParamID uint8 = 0x01 + ListObjectParamType uint8 = 0x02 ) diff --git a/connector/http.go b/connector/http.go index a31f23a..ca2f195 100644 --- a/connector/http.go +++ b/connector/http.go @@ -3,10 +3,11 @@ package connector import ( "bytes" "fmt" - "github.com/certusone/yubihsm-go/commands" "io/ioutil" "net/http" "strings" + + "github.com/certusone/yubihsm-go/commands" ) type ( diff --git a/manager.go b/manager.go index e682a02..3bdca77 100644 --- a/manager.go +++ b/manager.go @@ -3,11 +3,12 @@ package yubihsm import ( "bytes" "errors" + "sync" + "time" + "github.com/certusone/yubihsm-go/commands" "github.com/certusone/yubihsm-go/connector" "github.com/certusone/yubihsm-go/securechannel" - "sync" - "time" ) type ( @@ -70,7 +71,6 @@ func (s *SessionManager) pingRoutine() { } } - println("pinged") s.keepAlive.Reset(pingInterval) } } diff --git a/securechannel/channel.go b/securechannel/channel.go index 75fe8d0..dab6b49 100644 --- a/securechannel/channel.go +++ b/securechannel/channel.go @@ -7,10 +7,11 @@ import ( "crypto/rand" "encoding/binary" "errors" + "sync" + + "github.com/enceve/crypto/cmac" "github.com/certusone/yubihsm-go/commands" "github.com/certusone/yubihsm-go/connector" - "github.com/enceve/crypto/cmac" - "sync" ) type (