yubihsm-go/commands/constructors.go

419 lines
11 KiB
Go

package commands
import (
"bytes"
"encoding/binary"
"errors"
"io"
"github.com/certusone/yubihsm-go/authkey"
)
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
}
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 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
}
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
}
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 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
}
func CreateCloseSessionCommand() (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeCloseSession,
}
return command, nil
}
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
}
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,
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
}
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
}
func CreatePutOpaqueCommand(objID uint16, label []byte, domains uint16, capabilities uint64, algorithm Algorithm, data []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: CommandTypePutOpaque,
}
payload := bytes.NewBuffer(nil)
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)
payload.Write(data)
command.Data = payload.Bytes()
return command, nil
}
func CreateGetOpaqueCommand(objID uint16) (*CommandMessage, error) {
command := &CommandMessage{
CommandType: CommandTypeGetOpaque,
}
payload := bytes.NewBuffer(nil)
binary.Write(payload, binary.BigEndian, objID)
command.Data = payload.Bytes()
return command, nil
}
func CreateGetPseudoRandomCommand(numBytes uint16) *CommandMessage {
command := &CommandMessage{
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,
}
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(wrapkey)
command.Data = payload.Bytes()
return command, nil
}
func CreatePutAuthenticationKeyCommand(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: CommandTypePutAuthenticationKey,
}
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
}
func CreatePutDerivedAuthenticationKeyCommand(objID uint16, label []byte, domains uint16, capabilities uint64, delegated uint64, password string) (*CommandMessage, error) {
authKey := authkey.NewFromPassword(password)
return CreatePutAuthenticationKeyCommand(objID, label, domains, capabilities, delegated, authKey.GetEncKey(), authKey.GetMacKey())
}
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)
command.Data = payload.Bytes()
return command, nil
}