Skip to content

Commit

Permalink
conway: add new certificates
Browse files Browse the repository at this point in the history
  • Loading branch information
janmazak committed Nov 29, 2023
1 parent 6fcd3b1 commit 954c4eb
Show file tree
Hide file tree
Showing 15 changed files with 1,604 additions and 194 deletions.
20 changes: 10 additions & 10 deletions doc/ins_sign_tx.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,41 +242,41 @@ In addition, a transaction using `SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OPERATOR
| P1 | `0x06` |
| P2 | (unused / see [Stake Pool Registration](ins_sign_stake_pool_registration.md)) |

**Data for CERTIFICATE_TYPE_STAKE_REGISTRATION**
**Data for CERTIFICATE_STAKE_REGISTRATION**

|Field| Length | Comments|
|-----|--------|---------|
|Output type| 1 | `CERTIFICATE_TYPE_STAKE_REGISTRATION=0x00`|
|Output type| 1 | `CERTIFICATE_STAKE_REGISTRATION=0x00`|
|Stake credential| variable | See stake credential explained above|

**Data for CERTIFICATE_TYPE_STAKE_DEREGISTRATION**
**Data for CERTIFICATE_STAKE_DEREGISTRATION**

|Field| Length | Comments|
|-----|--------|---------|
|Output type| 1 | `CERTIFICATE_TYPE_STAKE_DEREGISTRATION=0x01`|
|Output type| 1 | `CERTIFICATE_STAKE_DEREGISTRATION=0x01`|
|Stake credential| variable | See stake credential explained above|

**Data for CERTIFICATE_TYPE_STAKE_DELEGATION**
**Data for CERTIFICATE_STAKE_DELEGATION**

|Field| Length | Comments|
|-----|--------|---------|
|Output type| 1 | `CERTIFICATE_TYPE_STAKE_DELEGATION=0x02`|
|Output type| 1 | `CERTIFICATE_STAKE_DELEGATION=0x02`|
|Stake credential| variable | See stake credential explained above|
|Pool key hash| 28 | Hash of staking pool public key|

**Data for CERTIFICATE_TYPE_STAKE_POOL_REGISTRATION**
**Data for CERTIFICATE_STAKE_POOL_REGISTRATION**

|Field| Length | Comments|
|-----|--------|---------|
|Output type| 1 | `CERTIFICATE_TYPE_STAKE_POOL_REGISTRATION=0x03`|
|Output type| 1 | `CERTIFICATE_STAKE_POOL_REGISTRATION=0x03`|

This only describes the initial certificate message. All the data for this certificate are obtained via a series of additional APDU messages; see [Stake Pool Registration](ins_sign_stake_pool_registration.md) for the details.

**Data for CERTIFICATE_TYPE_STAKE_POOL_RETIREMENT**
**Data for CERTIFICATE_STAKE_POOL_RETIREMENT**

|Field| Length | Comments|
|-----|--------|---------|
|Output type| 1 | `CERTIFICATE_TYPE_STAKE_POOL_RETIREMENT=0x04`|
|Output type| 1 | `CERTIFICATE_STAKE_POOL_RETIREMENT=0x04`|
|Stake key path| variable | BIP44 path. See [GetExtPubKey call](ins_get_public_keys.md) for a format example |
|Pool key hash| 28 | Hash of staking pool public key|

Expand Down
21 changes: 16 additions & 5 deletions src/cardano.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ STATIC_ASSERT(LOVELACE_MAX_SUPPLY < LOVELACE_INVALID, "bad LOVELACE_INVALID");
#define SCRIPT_HASH_LENGTH 28
#define SCRIPT_DATA_HASH_LENGTH 32
#define OUTPUT_DATUM_HASH_LENGTH 32
#define ANCHOR_HASH_LENGTH 32

#define MINTING_POLICY_ID_SIZE (SCRIPT_HASH_LENGTH)
#define ASSET_NAME_SIZE_MAX 32
Expand Down Expand Up @@ -100,6 +101,8 @@ typedef struct {

// ============================== CERTIFICATES ==============================

#define ANCHOR_URL_LENGTH_MAX 64

#define POOL_METADATA_URL_LENGTH_MAX 64
#define DNS_NAME_SIZE_MAX 64

Expand All @@ -111,11 +114,19 @@ typedef struct {

// there may be other types we do not support
typedef enum {
CERTIFICATE_TYPE_STAKE_REGISTRATION = 0,
CERTIFICATE_TYPE_STAKE_DEREGISTRATION = 1,
CERTIFICATE_TYPE_STAKE_DELEGATION = 2,
CERTIFICATE_TYPE_STAKE_POOL_REGISTRATION = 3,
CERTIFICATE_TYPE_STAKE_POOL_RETIREMENT = 4,
CERTIFICATE_STAKE_REGISTRATION = 0,
CERTIFICATE_STAKE_DEREGISTRATION = 1,
CERTIFICATE_STAKE_DELEGATION = 2,
CERTIFICATE_STAKE_POOL_REGISTRATION = 3,
CERTIFICATE_STAKE_POOL_RETIREMENT = 4,
CERTIFICATE_STAKE_REGISTRATION_CONWAY = 7,
CERTIFICATE_STAKE_DEREGISTRATION_CONWAY = 8,
CERTIFICATE_VOTE_DELEGATION = 9,
CERTIFICATE_AUTHORIZE_COMMITTEE_HOT = 14,
CERTIFICATE_RESIGN_COMMITTEE_COLD = 15,
CERTIFICATE_DREP_REGISTRATION = 16,
CERTIFICATE_DREP_DEREGISTRATION = 17,
CERTIFICATE_DREP_UPDATE = 18,
} certificate_type_t;

typedef enum {
Expand Down
214 changes: 157 additions & 57 deletions src/securityPolicy.c
Original file line number Diff line number Diff line change
Expand Up @@ -992,22 +992,22 @@ security_policy_t policyForSignTxCertificate(
case SIGN_TX_SIGNINGMODE_PLUTUS_TX:
case SIGN_TX_SIGNINGMODE_ORDINARY_TX:
// pool registration is allowed only in POOL_REGISTRATION signing modes
DENY_IF(certificateType == CERTIFICATE_TYPE_STAKE_POOL_REGISTRATION);
DENY_IF(certificateType == CERTIFICATE_STAKE_POOL_REGISTRATION);
ALLOW();
break;

case SIGN_TX_SIGNINGMODE_MULTISIG_TX:
// pool registration is allowed only in POOL_REGISTRATION signing modes
DENY_IF(certificateType == CERTIFICATE_TYPE_STAKE_POOL_REGISTRATION);
DENY_IF(certificateType == CERTIFICATE_STAKE_POOL_REGISTRATION);
// pool retirement is impossible with multisig keys
DENY_IF(certificateType == CERTIFICATE_TYPE_STAKE_POOL_RETIREMENT);
DENY_IF(certificateType == CERTIFICATE_STAKE_POOL_RETIREMENT);
ALLOW();
break;

case SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OPERATOR:
case SIGN_TX_SIGNINGMODE_POOL_REGISTRATION_OWNER:
// only pool registration is allowed
DENY_UNLESS(certificateType == CERTIFICATE_TYPE_STAKE_POOL_REGISTRATION);
DENY_UNLESS(certificateType == CERTIFICATE_STAKE_POOL_REGISTRATION);
ALLOW();
break;

Expand All @@ -1018,6 +1018,74 @@ security_policy_t policyForSignTxCertificate(
DENY(); // should not be reached
}

// applicable to credentials that are witnessed in this tx
static bool forbiddenCredential(
sign_tx_signingmode_t txSigningMode,
const ext_credential_t* credential
)
{
// certain combinations of tx signing mode and credential type are not allowed
// either because they don't make sense or are dangerous
switch (txSigningMode) {
case SIGN_TX_SIGNINGMODE_MULTISIG_TX:
switch (credential->type) {
case EXT_CREDENTIAL_KEY_PATH:
case EXT_CREDENTIAL_KEY_HASH:
// everything is expected to be governed by native scripts
return true;
default:
break;
}
break;

case SIGN_TX_SIGNINGMODE_PLUTUS_TX:
// everything allowed, txs are too complex for a HW wallet to understand
// and there might be third-party key hashes in the tx
break;

case SIGN_TX_SIGNINGMODE_ORDINARY_TX:
switch (credential->type) {
case EXT_CREDENTIAL_KEY_HASH:
case EXT_CREDENTIAL_SCRIPT_HASH:
// keys must be given by path, otherwise the user does not know
// if the hash corresponds to some of his keys,
// and might inadvertently sign several certificates with a single witness
return true;
default:
break;
}
break;

default:
// this should not be called in POOL_REGISTRATION signing modes
ASSERT(false);
break;
}

return false;
}

security_policy_t _policyForSignTxCertificateStakeCredential(
sign_tx_signingmode_t txSigningMode,
const ext_credential_t* stakeCredential
)
{
DENY_IF(forbiddenCredential(txSigningMode, stakeCredential));

switch (stakeCredential->type) {
case EXT_CREDENTIAL_KEY_PATH:
DENY_UNLESS(bip44_isOrdinaryStakingKeyPath(&stakeCredential->keyPath));
DENY_IF(violatesSingleAccountOrStoreIt(&stakeCredential->keyPath));
break;

default:
// the rest is OK, forbidden credentials have been dealt with above
break;
}

PROMPT();
}

// for certificates concerning stake keys and stake delegation
security_policy_t policyForSignTxCertificateStaking(
sign_tx_signingmode_t txSigningMode,
Expand All @@ -1026,81 +1094,111 @@ security_policy_t policyForSignTxCertificateStaking(
)
{
switch (certificateType) {
case CERTIFICATE_TYPE_STAKE_REGISTRATION:
case CERTIFICATE_TYPE_STAKE_DEREGISTRATION:
case CERTIFICATE_TYPE_STAKE_DELEGATION:
case CERTIFICATE_STAKE_REGISTRATION:
case CERTIFICATE_STAKE_REGISTRATION_CONWAY:
case CERTIFICATE_STAKE_DEREGISTRATION:
case CERTIFICATE_STAKE_DEREGISTRATION_CONWAY:
case CERTIFICATE_STAKE_DELEGATION:
break; // these are allowed

default:
ASSERT(false);
}

switch (stakeCredential->type) {
case EXT_CREDENTIAL_KEY_PATH:
DENY_UNLESS(bip44_isOrdinaryStakingKeyPath(&stakeCredential->keyPath));
DENY_IF(violatesSingleAccountOrStoreIt(&stakeCredential->keyPath));
switch (txSigningMode) {
case SIGN_TX_SIGNINGMODE_ORDINARY_TX:
case SIGN_TX_SIGNINGMODE_PLUTUS_TX:
PROMPT();
break;
return _policyForSignTxCertificateStakeCredential(txSigningMode, stakeCredential);
}

case SIGN_TX_SIGNINGMODE_MULTISIG_TX:
DENY();
break;
security_policy_t policyForSignTxCertificateVoteDelegation(
sign_tx_signingmode_t txSigningMode,
const ext_credential_t* stakeCredential,
const ext_drep_t* drep
)
{
// DRep can be anything, but if given by key path, it should be a valid path
if (drep->type == EXT_DREP_KEY_PATH) {
DENY_UNLESS(bip44_isDRepKeyPath(&drep->keyPath));
}

default:
// in POOL_REGISTRATION signing modes, this certificate should have already been
// reported as invalid (only pool registration certificate is allowed)
ASSERT(false);
break;
}
return _policyForSignTxCertificateStakeCredential(txSigningMode, stakeCredential);
}

security_policy_t policyForSignTxCertificateCommitteeAuth(
sign_tx_signingmode_t txSigningMode,
const ext_credential_t* coldCredential,
const ext_credential_t* hotCredential
)
{
DENY_IF(forbiddenCredential(txSigningMode, coldCredential));

switch (coldCredential->type) {
case EXT_CREDENTIAL_KEY_PATH:
DENY_UNLESS(bip44_isCommitteeColdKeyPath(&coldCredential->keyPath));
DENY_IF(violatesSingleAccountOrStoreIt(&coldCredential->keyPath));
break;

default:
// the rest is OK, forbidden credentials have been dealt with above
break;
}

switch (hotCredential->type) {

case EXT_CREDENTIAL_SCRIPT_HASH:
case EXT_CREDENTIAL_KEY_HASH:
switch (txSigningMode) {
case SIGN_TX_SIGNINGMODE_PLUTUS_TX:
PROMPT();
break;
// keys might be governed outside of this device
break;

case SIGN_TX_SIGNINGMODE_ORDINARY_TX:
case SIGN_TX_SIGNINGMODE_MULTISIG_TX:
DENY();
break;
case EXT_CREDENTIAL_KEY_PATH:
DENY_UNLESS(bip44_isCommitteeHotKeyPath(&hotCredential->keyPath));
break;

default:
// in POOL_REGISTRATION signing modes, this certificate should have already been
// reported as invalid (only pool registration certificate is allowed)
ASSERT(false);
break;
}
default:
ASSERT(false);
}

PROMPT();
}

security_policy_t policyForSignTxCertificateCommitteeResign(
sign_tx_signingmode_t txSigningMode,
const ext_credential_t* coldCredential
)
{
DENY_IF(forbiddenCredential(txSigningMode, coldCredential));

switch (coldCredential->type) {
case EXT_CREDENTIAL_KEY_PATH:
DENY_UNLESS(bip44_isCommitteeColdKeyPath(&coldCredential->keyPath));
DENY_IF(violatesSingleAccountOrStoreIt(&coldCredential->keyPath));
break;

case EXT_CREDENTIAL_SCRIPT_HASH:
switch (txSigningMode) {
case SIGN_TX_SIGNINGMODE_MULTISIG_TX:
case SIGN_TX_SIGNINGMODE_PLUTUS_TX:
PROMPT();
break;
default:
// the rest is OK, forbidden credentials have been dealt with above
break;
}

case SIGN_TX_SIGNINGMODE_ORDINARY_TX:
DENY();
break;
PROMPT();
}

default:
// in POOL_REGISTRATION signing modes, this certificate should have already been
// reported as invalid (only pool registration certificate is allowed)
ASSERT(false);
break;
}
security_policy_t policyForSignTxCertificateDRep(
sign_tx_signingmode_t txSigningMode,
const ext_credential_t* dRepCredential
)
{
DENY_IF(forbiddenCredential(txSigningMode, dRepCredential));

switch (dRepCredential->type) {
case EXT_CREDENTIAL_KEY_PATH:
DENY_UNLESS(bip44_isDRepKeyPath(&dRepCredential->keyPath));
DENY_IF(violatesSingleAccountOrStoreIt(&dRepCredential->keyPath));
break;

default:
ASSERT(false);
// the rest is OK, forbidden credentials have been dealt with above
break;
}

DENY(); // should not be reached
PROMPT();
}

#ifdef APP_FEATURE_POOL_RETIREMENT
Expand Down Expand Up @@ -1416,7 +1514,6 @@ static inline security_policy_t _ordinaryWitnessPolicy(const bip44_path_t* path,
case PATH_COMMITTEE_HOT_KEY:
// these have to be shown because the tx might contain
// an action proposal that cannot be fully shown on the device
// TODO what about violation of single account policy?
DENY_IF(violatesSingleAccountOrStoreIt(path));
WARN_UNLESS(bip44_isPathReasonable(path));
SHOW();
Expand Down Expand Up @@ -1478,6 +1575,9 @@ static inline security_policy_t _plutusWitnessPolicy(const bip44_path_t* path, b
case PATH_ORDINARY_STAKING_KEY:
case PATH_MULTISIG_SPENDING_KEY:
case PATH_MULTISIG_STAKING_KEY:
case PATH_DREP_KEY:
case PATH_COMMITTEE_COLD_KEY:
case PATH_COMMITTEE_HOT_KEY:
WARN_UNLESS(bip44_isPathReasonable(path));
SHOW();
break;
Expand Down
Loading

0 comments on commit 954c4eb

Please sign in to comment.