面试题答案
一键面试1. 状态机状态定义
- 初始状态(INIT):尚未开始握手流程。
- 客户端Hello(CLIENT_HELLO):客户端发送Hello消息,包含客户端支持的协议版本、随机数等信息。
- 服务器Hello(SERVER_HELLO):服务器收到客户端Hello后,回复服务器Hello消息,包含选定的协议版本、服务器随机数等信息。
- 服务器证书(SERVER_CERTIFICATE):服务器发送其数字证书。
- 客户端密钥交换(CLIENT_KEY_EXCHANGE):客户端根据服务器证书生成预主密钥并发送给服务器。
- 服务器密钥交换(SERVER_KEY_EXCHANGE):(部分情况下)服务器可能需要发送额外的密钥交换信息。
- 客户端完成(CLIENT_FINISHED):客户端验证服务器证书等信息后,发送Finished消息,表明客户端握手完成。
- 服务器完成(SERVER_FINISHED):服务器验证客户端信息后,发送Finished消息,表明服务器握手完成。
- 握手成功(HANDSHAKE_SUCCESS):双方握手成功,可进行加密通信。
2. 状态转移条件
- INIT -> CLIENT_HELLO:应用层发起握手请求。
- CLIENT_HELLO -> SERVER_HELLO:服务器成功接收并解析客户端Hello消息。
- SERVER_HELLO -> SERVER_CERTIFICATE:服务器准备好发送证书。
- SERVER_CERTIFICATE -> CLIENT_KEY_EXCHANGE:客户端成功接收并验证服务器证书。
- CLIENT_KEY_EXCHANGE -> SERVER_KEY_EXCHANGE:(部分情况)服务器需要进一步的密钥交换。
- SERVER_KEY_EXCHANGE -> CLIENT_FINISHED:客户端完成密钥计算等准备。
- CLIENT_FINISHED -> SERVER_FINISHED:服务器成功接收并验证客户端Finished消息。
- SERVER_FINISHED -> HANDSHAKE_SUCCESS:客户端成功接收并验证服务器Finished消息。
3. 数据结构设计
// 定义状态枚举类型
typedef enum {
INIT,
CLIENT_HELLO,
SERVER_HELLO,
SERVER_CERTIFICATE,
CLIENT_KEY_EXCHANGE,
SERVER_KEY_EXCHANGE,
CLIENT_FINISHED,
SERVER_FINISHED,
HANDSHAKE_SUCCESS
} State;
// 状态机上下文结构体
typedef struct {
State currentState;
// 存储握手过程中的相关数据,如随机数、证书等
char clientRandom[32];
char serverRandom[32];
char serverCertificate[2048];
char preMasterSecret[48];
} StateMachineContext;
4. 状态转移函数编写思路
- 初始化函数:
void initStateMachine(StateMachineContext *context) {
context->currentState = INIT;
// 初始化其他数据
memset(context->clientRandom, 0, sizeof(context->clientRandom));
memset(context->serverRandom, 0, sizeof(context->serverRandom));
memset(context->serverCertificate, 0, sizeof(context->serverCertificate));
memset(context->preMasterSecret, 0, sizeof(context->preMasterSecret));
}
- 状态转移函数示例(以CLIENT_HELLO -> SERVER_HELLO为例):
void handleClientHello(StateMachineContext *context, const char *clientHelloMsg) {
if (context->currentState != CLIENT_HELLO) {
// 错误处理,当前状态不应该是CLIENT_HELLO
return;
}
// 解析clientHelloMsg,提取客户端随机数等信息
sscanf(clientHelloMsg, "random=%31s", context->clientRandom);
// 转移到SERVER_HELLO状态
context->currentState = SERVER_HELLO;
}
- 通用的状态转移函数模板:
void transitionState(StateMachineContext *context, State newState) {
context->currentState = newState;
// 可以根据状态转移进行一些通用的数据清理或初始化操作
}
在实际实现中,还需要结合网络编程相关函数(如socket函数)来发送和接收握手消息,并对消息进行正确的解析和验证。同时,要处理错误情况,如消息格式错误、证书验证失败等,以确保状态机的健壮性。