yubihsm-go/commands/constructors.go

462 lines
12 KiB
Go
Raw Permalink Normal View History

2018-09-02 05:46:37 -07:00
package commands
import (
"bytes"
"encoding/binary"
"errors"
"io"
"github.com/certusone/yubihsm-go/authkey"
2018-09-02 05:46:37 -07:00
)
2022-06-15 16:54:59 -07:00
func CreateDeviceInfoCommand() (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeDeviceInfo,
}
return command, nil
}
2018-09-02 05:46:37 -07:00
func CreateCreateSessionCommand(keySetID uint16, hostChallenge []byte) (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeCreateSession,
}
payload := bytes.NewBuffer([]byte{})
binary.Write(payload, binary.BigEndian, keySetID)
payload.Write(hostChallenge)
command.Data = payload.Bytes()
return command, nil
}
func CreateAuthenticateSessionCommand(hostCryptogram []byte) (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeAuthenticateSession,
Data: hostCryptogram,
}
return command, nil
}
// Authenticated
func CreateResetCommand() (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeReset,
}
return command, nil
}
func CreateGenerateAsymmetricKeyCommand(keyID uint16, label []byte, domains uint16, capabilities uint64, algorithm Algorithm) (*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))...)
}
command := &CommandMessage{
CommandType: CommandTypeGenerateAsymmetricKey,
}
payload := bytes.NewBuffer([]byte{})
binary.Write(payload, binary.BigEndian, keyID)
payload.Write(label)
binary.Write(payload, binary.BigEndian, domains)
binary.Write(payload, binary.BigEndian, capabilities)
binary.Write(payload, binary.BigEndian, algorithm)
command.Data = payload.Bytes()
return command, nil
}
func CreateSignDataEddsaCommand(keyID uint16, data []byte) (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeSignDataEddsa,
}
payload := bytes.NewBuffer([]byte{})
binary.Write(payload, binary.BigEndian, keyID)
payload.Write(data)
command.Data = payload.Bytes()
return command, nil
}
2018-11-30 07:49:18 -08:00
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
}
2021-04-07 15:05:46 -07:00
func CreateSignDataPkcs1Command(keyID uint16, data []byte) (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeSignDataPkcs1,
}
payload := bytes.NewBuffer([]byte{})
binary.Write(payload, binary.BigEndian, keyID)
payload.Write(data)
command.Data = payload.Bytes()
return command, nil
}
2018-09-02 05:46:37 -07:00
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")
}
if len(label) < LabelLength {
label = append(label, bytes.Repeat([]byte{0x00}, LabelLength-len(label))...)
}
command := &CommandMessage{
CommandType: CommandTypePutAsymmetric,
}
payload := bytes.NewBuffer([]byte{})
binary.Write(payload, binary.BigEndian, keyID)
payload.Write(label)
binary.Write(payload, binary.BigEndian, domains)
binary.Write(payload, binary.BigEndian, capabilities)
binary.Write(payload, binary.BigEndian, algorithm)
payload.Write(keyPart1)
if keyPart2 != nil {
payload.Write(keyPart2)
}
command.Data = payload.Bytes()
return command, nil
}
2018-09-02 10:26:39 -07:00
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)
}
}
2021-04-07 14:22:09 -07:00
func NewDomainOption(domain uint16) ListCommandOption {
return func(w io.Writer) {
binary.Write(w, binary.BigEndian, ListObjectParamDomains)
binary.Write(w, binary.BigEndian, domain)
}
}
func NewLabelOption(label []byte) (ListCommandOption, 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))...)
}
return func(w io.Writer) {
binary.Write(w, binary.BigEndian, ListObjectParamLabel)
binary.Write(w, binary.BigEndian, label)
}, nil
}
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
}
2018-09-02 10:26:39 -07:00
func CreateCloseSessionCommand() (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeCloseSession,
}
return command, nil
}
2018-09-08 11:43:08 -07:00
func CreateGetPubKeyCommand(keyID uint16) (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeGetPubKey,
}
payload := bytes.NewBuffer([]byte{})
binary.Write(payload, binary.BigEndian, keyID)
command.Data = payload.Bytes()
return command, nil
}
2018-09-14 03:21:34 -07:00
2018-12-05 05:42:38 -08:00
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
}
2018-09-14 03:21:34 -07:00
func CreateEchoCommand(data []byte) (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeEcho,
Data: data,
}
return command, nil
}
func CreateDeriveEcdhCommand(objID uint16, pubkey []byte) (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeDeriveEcdh,
}
payload := bytes.NewBuffer([]byte{})
binary.Write(payload, binary.BigEndian, objID)
payload.Write(pubkey)
command.Data = payload.Bytes()
return command, nil
}
2021-04-07 14:22:09 -07:00
func CreateChangeAuthenticationKeyCommand(objID uint16, newPassword string) (*CommandMessage, error) {
2021-03-01 03:47:30 -08:00
command := &CommandMessage{
2021-04-07 14:22:09 -07:00
CommandType: CommandTypeChangeAuthenticationKey,
2021-03-01 03:47:30 -08:00
}
2021-04-07 14:22:09 -07:00
authKey := authkey.NewFromPassword(newPassword)
2021-03-01 03:47:30 -08:00
payload := bytes.NewBuffer([]byte{})
2021-04-07 14:22:09 -07:00
binary.Write(payload, binary.BigEndian, objID)
binary.Write(payload, binary.BigEndian, AlgorithmYubicoAESAuthentication)
payload.Write(authKey.GetEncKey())
payload.Write(authKey.GetMacKey())
2021-03-01 03:47:30 -08:00
command.Data = payload.Bytes()
2021-04-07 14:22:09 -07:00
return command, nil
2021-03-01 03:47:30 -08:00
}
2021-03-04 07:46:36 -08:00
2021-04-07 14:22:09 -07:00
func CreatePutOpaqueCommand(objID uint16, label []byte, domains uint16, capabilities uint64, algorithm Algorithm, data []byte) (*CommandMessage, error) {
2021-03-04 07:46:36 -08:00
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))...)
}
command := &CommandMessage{
2021-04-07 14:22:09 -07:00
CommandType: CommandTypePutOpaque,
2021-03-04 07:46:36 -08:00
}
2021-04-07 14:22:09 -07:00
payload := bytes.NewBuffer(nil)
2021-03-04 07:46:36 -08:00
binary.Write(payload, binary.BigEndian, objID)
payload.Write(label)
binary.Write(payload, binary.BigEndian, domains)
binary.Write(payload, binary.BigEndian, capabilities)
2021-03-05 04:00:28 -08:00
binary.Write(payload, binary.BigEndian, algorithm)
2021-04-07 14:22:09 -07:00
payload.Write(data)
2021-03-04 07:46:36 -08:00
command.Data = payload.Bytes()
return command, nil
}
2021-03-05 04:41:57 -08:00
2021-04-07 14:22:09 -07:00
func CreateGetOpaqueCommand(objID uint16) (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeGetOpaque,
2021-03-05 04:41:57 -08:00
}
2021-04-07 14:22:09 -07:00
payload := bytes.NewBuffer(nil)
binary.Write(payload, binary.BigEndian, objID)
command.Data = payload.Bytes()
return command, nil
}
2021-04-07 15:05:46 -07:00
func CreateGetPseudoRandomCommand(numBytes uint16) *CommandMessage {
2021-03-05 04:41:57 -08:00
command := &CommandMessage{
2021-04-07 15:05:46 -07:00
CommandType: CommandTypeGetPseudoRandom,
}
payload := bytes.NewBuffer([]byte{})
binary.Write(payload, binary.BigEndian, numBytes)
command.Data = payload.Bytes()
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,
2021-03-05 04:41:57 -08:00
}
payload := bytes.NewBuffer([]byte{})
binary.Write(payload, binary.BigEndian, objID)
2021-04-07 15:05:46 -07:00
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
}
2021-04-09 10:44:16 -07:00
func CreatePutAuthkeyCommand(objID uint16, label []byte, domains uint16, capabilities, delegated uint64, encKey, macKey []byte) (*CommandMessage, error) {
2021-04-07 15:05:46 -07:00
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{
2021-04-09 10:44:16 -07:00
CommandType: CommandTypePutAuthKey,
2021-04-07 15:05:46 -07:00
}
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)
2021-04-07 14:22:09 -07:00
command.Data = payload.Bytes()
return command, nil
}
2021-04-07 15:05:46 -07:00
func CreatePutDerivedAuthenticationKeyCommand(objID uint16, label []byte, domains uint16, capabilities uint64, delegated uint64, password string) (*CommandMessage, error) {
authKey := authkey.NewFromPassword(password)
2021-04-09 10:44:16 -07:00
return CreatePutAuthkeyCommand(objID, label, domains, capabilities, delegated, authKey.GetEncKey(), authKey.GetMacKey())
2021-04-07 15:05:46 -07:00
}
2021-04-07 14:22:09 -07:00
func CreateSignAttestationCertCommand(keyObjID, attestationObjID uint16) (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeAttestAsymmetric,
}
payload := bytes.NewBuffer([]byte{})
binary.Write(payload, binary.BigEndian, keyObjID)
binary.Write(payload, binary.BigEndian, attestationObjID)
2021-06-17 04:28:14 -07:00
command.Data = payload.Bytes()
return command, nil
}
func CreateExportWrappedCommand(wrapObjID uint16, objType uint8, objID uint16) (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeExportWrapped,
}
2021-03-05 04:41:57 -08:00
2021-06-17 04:28:14 -07:00
payload := bytes.NewBuffer([]byte{})
binary.Write(payload, binary.BigEndian, wrapObjID)
binary.Write(payload, binary.BigEndian, objType)
binary.Write(payload, binary.BigEndian, objID)
2021-03-05 04:41:57 -08:00
command.Data = payload.Bytes()
return command, nil
}
2021-06-17 10:59:00 -07:00
// 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 objects
// 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
}