in source/session.c [388:538]
void aws_cryptosdk_priv_session_change_state(struct aws_cryptosdk_session *session, enum session_state new_state) {
// Performs internal sanity checks before allowing a state change.
// Since the intent is mostly to avoid use of initialized memory due to internal bugs, we
// simply abort if something went wrong.
// We can change this to enter an error state instead in the future if necessary.
if (session->state == new_state) {
// no-op
return;
}
if (session->state == ST_ERROR) {
// Can't leave ST_ERROR except by reinitializing
if (new_state != ST_CONFIG) {
abort();
}
}
switch (new_state) {
case ST_ERROR: // fall through
case ST_CONFIG:
break; // no initialization required, and we can transition from any other state
/***** Decrypt path *****/
case ST_READ_HEADER:
if (session->state != ST_CONFIG) {
// Illegal transition
abort();
}
if (!aws_cryptosdk_priv_is_decrypt_mode(session->mode)) {
// wrong mode
abort();
}
break;
case ST_UNWRAP_KEY:
if (session->state != ST_READ_HEADER) {
// Illegal transition
abort();
}
if (!aws_cryptosdk_priv_is_decrypt_mode(session->mode)) {
// wrong mode
abort();
}
// check that a few of the more important state values are configured
if (!session->header_copy || !session->header_size) {
abort();
}
break;
case ST_DECRYPT_BODY:
if (session->state != ST_UNWRAP_KEY) {
// Illegal transition
break;
}
if (!session->alg_props) {
// algorithm properties not set
abort();
}
if (session->frame_seqno == 0) {
// illegal sequence number
abort();
}
// we can't currently assert that the data key is present because
// it might be all-zero (for example)
break;
case ST_CHECK_TRAILER:
if (session->state != ST_DECRYPT_BODY) {
abort(); // Illegal transition
}
break;
/***** Encrypt path *****/
case ST_GEN_KEY:
if (session->state != ST_CONFIG) {
// illegal transition
abort();
}
if (session->mode != AWS_CRYPTOSDK_ENCRYPT) {
// Bad state
abort();
}
// TODO check for KR config/etc?
break;
case ST_WRITE_HEADER: {
if (session->mode != AWS_CRYPTOSDK_ENCRYPT) {
// wrong mode
abort();
}
if (ST_GEN_KEY != session->state) {
// Illegal transition
abort();
}
// We should have generated the header, and should now be ready to write it.
if (!session->header_copy || !session->header_size) {
abort();
}
break;
}
case ST_ENCRYPT_BODY: {
if (ST_WRITE_HEADER != session->state) {
// Illegal transition
abort();
}
if (!session->alg_props) {
// algorithm properties not set
abort();
}
if (session->frame_seqno == 0) {
// illegal sequence number
abort();
}
// we can't currently assert that the data key is present because, well, it might be all-zero
break;
}
case ST_WRITE_TRAILER:
if (session->state != ST_ENCRYPT_BODY) {
// illegal transition
abort();
}
break;
case ST_DONE:
switch (session->state) {
case ST_ENCRYPT_BODY: // ok, fall through
case ST_DECRYPT_BODY: // ok, fall through
case ST_CHECK_TRAILER: // ok, fall through
case ST_WRITE_TRAILER: // ok, fall through
break;
default: // Illegal transition
abort();
}
break;
}
session->state = new_state;
}