Add ChangeAuthenticationKey command

Introduce the command which is used to change the password to
authenticate to the HSM.

A small refactoring of extracting authkey out was necessary to prevent
an import cycle from securechannel importing commands which (without the
refactor) imported secure channel again.

Documentation for this command: https://developers.yubico.com/YubiHSM2/Commands/Change_Authentication_Key.html
This commit is contained in:
Jake Craige 2020-02-28 09:40:45 -08:00
parent d0ca2ed0df
commit 530348283f
No known key found for this signature in database
GPG Key ID: 73EB8ECDAC6DCCE1
6 changed files with 102 additions and 59 deletions

View File

@ -13,6 +13,7 @@ Currently the following commands are implemented:
* GetPubKey * GetPubKey
* DeriveEcdh * DeriveEcdh
* Echo * Echo
* ChangeAuthenticationKey
* Authentication & Session related commands * Authentication & Session related commands
Implementing new commands is really easy. Please consult `commands/constructors.go` and `commands/response.go` for reference. Implementing new commands is really easy. Please consult `commands/constructors.go` and `commands/response.go` for reference.

View File

@ -1,7 +1,8 @@
package securechannel package authkey
import ( import (
"crypto/sha256" "crypto/sha256"
"golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/pbkdf2"
) )
@ -16,17 +17,17 @@ const (
yubicoSeed = "Yubico" yubicoSeed = "Yubico"
) )
// deriveAuthKeyFromPwd derives an AuthKey using pkdf2 as specified in the HSM documentation // NewFromPassword derives an AuthKey using pkdf2 as specified in the HSM documentation
func deriveAuthKeyFromPwd(password string) AuthKey { func NewFromPassword(password string) AuthKey {
return pbkdf2.Key([]byte(password), []byte(yubicoSeed), authKeyIterations, authKeyLength, sha256.New) return pbkdf2.Key([]byte(password), []byte(yubicoSeed), authKeyIterations, authKeyLength, sha256.New)
} }
// GetEncKey returns the EncryptionKey part of the AuthKey // GetEncKey returns the EncryptionKey part of the AuthKey
func (k AuthKey) GetEncKey() []byte { func (k AuthKey) GetEncKey() []byte {
return k[:KeyLength] return k[:authKeyLength/2]
} }
// GetEncKey returns the MACKey part of the AuthKey // GetMacKey returns the MACKey part of the AuthKey
func (k AuthKey) GetMacKey() []byte { func (k AuthKey) GetMacKey() []byte {
return k[KeyLength:] return k[authKeyLength/2:]
} }

View File

@ -5,6 +5,8 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"io" "io"
"github.com/certusone/yubihsm-go/authkey"
) )
func CreateCreateSessionCommand(keySetID uint16, hostChallenge []byte) (*CommandMessage, error) { func CreateCreateSessionCommand(keySetID uint16, hostChallenge []byte) (*CommandMessage, error) {
@ -218,3 +220,19 @@ func CreateDeriveEcdhCommand(objID uint16, pubkey []byte) (*CommandMessage, erro
return command, nil return command, nil
} }
func CreateChangeAuthenticationKeyCommand(objID uint16, newPassword string) (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeChangeAuthenticationKey,
}
authKey := authkey.NewFromPassword(newPassword)
payload := bytes.NewBuffer([]byte{})
binary.Write(payload, binary.BigEndian, objID)
binary.Write(payload, binary.BigEndian, AlgorithmYubicoAESAuthentication)
payload.Write(authKey.GetEncKey())
payload.Write(authKey.GetMacKey())
command.Data = payload.Bytes()
return command, nil
}

View File

@ -79,6 +79,10 @@ type (
DeriveEcdhResponse struct { DeriveEcdhResponse struct {
XCoordinate []byte XCoordinate []byte
} }
ChangeAuthenticationKeyResponse struct {
ObjectID uint16
}
) )
// ParseResponse parses the binary response from the card to the relevant Response type. // ParseResponse parses the binary response from the card to the relevant Response type.
@ -131,6 +135,8 @@ func ParseResponse(data []byte) (Response, error) {
return parseEchoResponse(payload) return parseEchoResponse(payload)
case CommandTypeDeriveEcdh: case CommandTypeDeriveEcdh:
return parseDeriveEcdhResponse(payload) return parseDeriveEcdhResponse(payload)
case CommandTypeChangeAuthenticationKey:
return parseChangeAuthenticationKeyResponse(payload)
case ErrorResponseCode: case ErrorResponseCode:
return nil, parseErrorResponse(payload) return nil, parseErrorResponse(payload)
default: default:
@ -262,6 +268,20 @@ func parseDeriveEcdhResponse(payload []byte) (Response, error) {
}, nil }, nil
} }
func parseChangeAuthenticationKeyResponse(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 &ChangeAuthenticationKeyResponse{ObjectID: objectID}, nil
}
// Error formats a card error message into a human readable format // Error formats a card error message into a human readable format
func (e *Error) Error() string { func (e *Error) Error() string {
message := "" message := ""

View File

@ -13,54 +13,55 @@ const (
// LabelLength is the max length of a label // LabelLength is the max length of a label
LabelLength = 40 LabelLength = 40
CommandTypeEcho CommandType = 0x01 CommandTypeEcho CommandType = 0x01
CommandTypeCreateSession CommandType = 0x03 CommandTypeCreateSession CommandType = 0x03
CommandTypeAuthenticateSession CommandType = 0x04 CommandTypeAuthenticateSession CommandType = 0x04
CommandTypeSessionMessage CommandType = 0x05 CommandTypeSessionMessage CommandType = 0x05
CommandTypeDeviceInfo CommandType = 0x06 CommandTypeDeviceInfo CommandType = 0x06
CommandTypeReset CommandType = 0x08 CommandTypeReset CommandType = 0x08
CommandTypeCloseSession CommandType = 0x40 CommandTypeCloseSession CommandType = 0x40
CommandTypeStorageStatus CommandType = 0x41 CommandTypeStorageStatus CommandType = 0x41
CommandTypePutOpaque CommandType = 0x42 CommandTypePutOpaque CommandType = 0x42
CommandTypeGetOpaque CommandType = 0x43 CommandTypeGetOpaque CommandType = 0x43
CommandTypePutAuthKey CommandType = 0x44 CommandTypePutAuthKey CommandType = 0x44
CommandTypePutAsymmetric CommandType = 0x45 CommandTypePutAsymmetric CommandType = 0x45
CommandTypeGenerateAsymmetricKey CommandType = 0x46 CommandTypeGenerateAsymmetricKey CommandType = 0x46
CommandTypeSignDataPkcs1 CommandType = 0x47 CommandTypeSignDataPkcs1 CommandType = 0x47
CommandTypeListObjects CommandType = 0x48 CommandTypeListObjects CommandType = 0x48
CommandTypeDecryptPkcs1 CommandType = 0x49 CommandTypeDecryptPkcs1 CommandType = 0x49
CommandTypeExportWrapped CommandType = 0x4a CommandTypeExportWrapped CommandType = 0x4a
CommandTypeImportWrapped CommandType = 0x4b CommandTypeImportWrapped CommandType = 0x4b
CommandTypePutWrapKey CommandType = 0x4c CommandTypePutWrapKey CommandType = 0x4c
CommandTypeGetLogs CommandType = 0x4d CommandTypeGetLogs CommandType = 0x4d
CommandTypeGetObjectInfo CommandType = 0x4e CommandTypeGetObjectInfo CommandType = 0x4e
CommandTypePutOption CommandType = 0x4f CommandTypePutOption CommandType = 0x4f
CommandTypeGetOption CommandType = 0x50 CommandTypeGetOption CommandType = 0x50
CommandTypeGetPseudoRandom CommandType = 0x51 CommandTypeGetPseudoRandom CommandType = 0x51
CommandTypePutHMACKey CommandType = 0x52 CommandTypePutHMACKey CommandType = 0x52
CommandTypeHMACData CommandType = 0x53 CommandTypeHMACData CommandType = 0x53
CommandTypeGetPubKey CommandType = 0x54 CommandTypeGetPubKey CommandType = 0x54
CommandTypeSignDataPss CommandType = 0x55 CommandTypeSignDataPss CommandType = 0x55
CommandTypeSignDataEcdsa CommandType = 0x56 CommandTypeSignDataEcdsa CommandType = 0x56
CommandTypeDecryptEcdh CommandType = 0x57 // here for backwards compatibility CommandTypeDecryptEcdh CommandType = 0x57 // here for backwards compatibility
CommandTypeDeriveEcdh CommandType = 0x57 CommandTypeDeriveEcdh CommandType = 0x57
CommandTypeDeleteObject CommandType = 0x58 CommandTypeDeleteObject CommandType = 0x58
CommandTypeDecryptOaep CommandType = 0x59 CommandTypeDecryptOaep CommandType = 0x59
CommandTypeGenerateHMACKey CommandType = 0x5a CommandTypeGenerateHMACKey CommandType = 0x5a
CommandTypeGenerateWrapKey CommandType = 0x5b CommandTypeGenerateWrapKey CommandType = 0x5b
CommandTypeVerifyHMAC CommandType = 0x5c CommandTypeVerifyHMAC CommandType = 0x5c
CommandTypeOTPDecrypt CommandType = 0x60 CommandTypeOTPDecrypt CommandType = 0x60
CommandTypeOTPAeadCreate CommandType = 0x61 CommandTypeOTPAeadCreate CommandType = 0x61
CommandTypeOTPAeadRandom CommandType = 0x62 CommandTypeOTPAeadRandom CommandType = 0x62
CommandTypeOTPAeadRewrap CommandType = 0x63 CommandTypeOTPAeadRewrap CommandType = 0x63
CommandTypeAttestAsymmetric CommandType = 0x64 CommandTypeAttestAsymmetric CommandType = 0x64
CommandTypePutOTPAeadKey CommandType = 0x65 CommandTypePutOTPAeadKey CommandType = 0x65
CommandTypeGenerateOTPAeadKey CommandType = 0x66 CommandTypeGenerateOTPAeadKey CommandType = 0x66
CommandTypeSetLogIndex CommandType = 0x67 CommandTypeSetLogIndex CommandType = 0x67
CommandTypeWrapData CommandType = 0x68 CommandTypeWrapData CommandType = 0x68
CommandTypeUnwrapData CommandType = 0x69 CommandTypeUnwrapData CommandType = 0x69
CommandTypeSignDataEddsa CommandType = 0x6a CommandTypeSignDataEddsa CommandType = 0x6a
CommandTypeSetBlink CommandType = 0x6b CommandTypeSetBlink CommandType = 0x6b
CommandTypeChangeAuthenticationKey CommandType = 0x6c
// Errors // Errors
ErrorCodeOK ErrorCode = 0x00 ErrorCodeOK ErrorCode = 0x00
@ -79,9 +80,10 @@ const (
ErrorCodeCommandUnexecuted ErrorCode = 0xff ErrorCodeCommandUnexecuted ErrorCode = 0xff
// Algorithms // Algorithms
AlgorithmP256 Algorithm = 12 AlgorithmP256 Algorithm = 12
AlgorithmSecp256k1 Algorithm = 15 AlgorithmSecp256k1 Algorithm = 15
AlgorighmED25519 Algorithm = 46 AlgorighmED25519 Algorithm = 46
AlgorithmYubicoAESAuthentication Algorithm = 38
// Capabilities // Capabilities
CapabilityGetOpaque uint64 = 0x0000000000000001 CapabilityGetOpaque uint64 = 0x0000000000000001

View File

@ -10,6 +10,7 @@ import (
"sync" "sync"
"github.com/enceve/crypto/cmac" "github.com/enceve/crypto/cmac"
"github.com/certusone/yubihsm-go/authkey"
"github.com/certusone/yubihsm-go/commands" "github.com/certusone/yubihsm-go/commands"
"github.com/certusone/yubihsm-go/connector" "github.com/certusone/yubihsm-go/connector"
) )
@ -39,7 +40,7 @@ type (
DeviceChallenge []byte DeviceChallenge []byte
// AuthKey to authenticate against the HSM; must match authKeySlot // AuthKey to authenticate against the HSM; must match authKeySlot
AuthKey AuthKey AuthKey authkey.AuthKey
// MACChainValue is the last MAC to allow MAC chaining // MACChainValue is the last MAC to allow MAC chaining
MACChainValue []byte MACChainValue []byte
@ -89,7 +90,7 @@ const (
func NewSecureChannel(connector connector.Connector, authKeySlot uint16, password string) (*SecureChannel, error) { func NewSecureChannel(connector connector.Connector, authKeySlot uint16, password string) (*SecureChannel, error) {
channel := &SecureChannel{ channel := &SecureChannel{
ID: 0, ID: 0,
AuthKey: deriveAuthKeyFromPwd(password), AuthKey: authkey.NewFromPassword(password),
MACChainValue: make([]byte, 16), MACChainValue: make([]byte, 16),
SecurityLevel: SecurityLevelUnauthenticated, SecurityLevel: SecurityLevelUnauthenticated,
authKeySlot: authKeySlot, authKeySlot: authKeySlot,