Reputation: 3
I'm working with civetweb and openssl-1.1.0h. I need to create a network that works with multiple clients. The communication between the server and clients should be encrypted with pre-shared keys.
In my understanding, while a connection is established, the callbacks psk_server_cb and psk_client_cb are called from the server side and client side respectively. These are the points to update the server and client pre-shared keys.
Suppose i have the information needed to know which pre-shared key to use for which client connection, how can i know, during the callback psk_server_cb (server side), to which client i open the connection (in order to know which psk i need to update during this callback)?
Will appreciate any help,
Tzipi
Additional information:
psk_server_cb prototype:
static unsigned int psk_server_cb(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len)
SSL structure:
struct ssl_st
{
/*
* protocol version (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION,
* DTLS1_VERSION)
*/
int version;
/* SSLv3 */
const SSL_METHOD *method;
/*
* There are 2 BIO's even though they are normally both the same. This
* is so data can be read and written to different handlers
*/
/* used by SSL_read */
BIO *rbio;
/* used by SSL_write */
BIO *wbio;
/* used during session-id reuse to concatenate messages */
BIO *bbio;
/*
* This holds a variable that indicates what we were doing when a 0 or -1
* is returned. This is needed for non-blocking IO so we know what
* request needs re-doing when in SSL_accept or SSL_connect
*/
int rwstate;
int (*handshake_func) (SSL *);
/*
* Imagine that here's a boolean member "init" that is switched as soon
* as SSL_set_{accept/connect}_state is called for the first time, so
* that "state" and "handshake_func" are properly initialized. But as
* handshake_func is == 0 until then, we use this test instead of an
* "init" member.
*/
/* are we the server side? */
int server;
/*
* Generate a new session or reuse an old one.
* NB: For servers, the 'new' session may actually be a previously
* cached session or even the previous session unless
* SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set
*/
int new_session;
/* don't send shutdown packets */
int quiet_shutdown;
/* we have shut things down, 0x01 sent, 0x02 for received */
int shutdown;
/* where we are */
OSSL_STATEM statem;
BUF_MEM *init_buf; /* buffer used during init */
void *init_msg; /* pointer to handshake message body, set by
* ssl3_get_message() */
int init_num; /* amount read/written */
int init_off; /* amount read/written */
struct ssl3_state_st *s3; /* SSLv3 variables */
struct dtls1_state_st *d1; /* DTLSv1 variables */
/* callback that allows applications to peek at protocol messages */
void (*msg_callback) (int write_p, int version, int content_type,
const void *buf, size_t len, SSL *ssl, void *arg);
void *msg_callback_arg;
int hit; /* reusing a previous session */
X509_VERIFY_PARAM *param;
/* Per connection DANE state */
SSL_DANE dane;
/* crypto */
STACK_OF(SSL_CIPHER) *cipher_list;
STACK_OF(SSL_CIPHER) *cipher_list_by_id;
/*
* These are the ones being used, the ones in SSL_SESSION are the ones to
* be 'copied' into these ones
*/
uint32_t mac_flags;
EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
EVP_MD_CTX *read_hash; /* used for mac generation */
COMP_CTX *compress; /* compression */
COMP_CTX *expand; /* uncompress */
EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
EVP_MD_CTX *write_hash; /* used for mac generation */
/* session info */
/* client cert? */
/* This is used to hold the server certificate used */
struct cert_st /* CERT */ *cert;
/*
* the session_id_context is used to ensure sessions are only reused in
* the appropriate context
*/
unsigned int sid_ctx_length;
unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
/* This can also be in the session once a session is established */
SSL_SESSION *session;
/* Default generate session ID callback. */
GEN_SESSION_CB generate_session_id;
/* Used in SSL3 */
/*
* 0 don't care about verify failure.
* 1 fail if verify fails
*/
uint32_t verify_mode;
/* fail if callback returns 0 */
int (*verify_callback) (int ok, X509_STORE_CTX *ctx);
/* optional informational callback */
void (*info_callback) (const SSL *ssl, int type, int val);
/* error bytes to be written */
int error;
/* actual code */
int error_code;
# ifndef OPENSSL_NO_PSK
unsigned int (*psk_client_callback) (SSL *ssl, const char *hint,
char *identity,
unsigned int max_identity_len,
unsigned char *psk,
unsigned int max_psk_len);
unsigned int (*psk_server_callback) (SSL *ssl, const char *identity,
unsigned char *psk,
unsigned int max_psk_len);
# endif
SSL_CTX *ctx;
/* Verified chain of peer */
STACK_OF(X509) *verified_chain;
long verify_result;
/* extra application data */
CRYPTO_EX_DATA ex_data;
/* for server side, keep the list of CA_dn we can use */
STACK_OF(X509_NAME) *client_CA;
int references;
/* protocol behaviour */
uint32_t options;
/* API behaviour */
uint32_t mode;
int min_proto_version;
int max_proto_version;
long max_cert_list;
int first_packet;
/* what was passed, used for SSLv3/TLS rollback check */
int client_version;
/*
* If we're using more than one pipeline how should we divide the data
* up between the pipes?
*/
unsigned int split_send_fragment;
/*
* Maximum amount of data to send in one fragment. actual record size can
* be more than this due to padding and MAC overheads.
*/
unsigned int max_send_fragment;
/* Up to how many pipelines should we use? If 0 then 1 is assumed */
unsigned int max_pipelines;
/* TLS extension debug callback */
void (*tlsext_debug_cb) (SSL *s, int client_server, int type,
const unsigned char *data, int len, void *arg);
void *tlsext_debug_arg;
char *tlsext_hostname;
/*-
* no further mod of servername
* 0 : call the servername extension callback.
* 1 : prepare 2, allow last ack just after in server callback.
* 2 : don't call servername callback, no ack in server hello
*/
int servername_done;
/* certificate status request info */
/* Status type or -1 if no status type */
int tlsext_status_type;
# ifndef OPENSSL_NO_CT
/*
* Validates that the SCTs (Signed Certificate Timestamps) are sufficient.
* If they are not, the connection should be aborted.
*/
ssl_ct_validation_cb ct_validation_callback;
/* User-supplied argument tha tis passed to the ct_validation_callback */
void *ct_validation_callback_arg;
/*
* Consolidated stack of SCTs from all sources.
* Lazily populated by CT_get_peer_scts(SSL*)
*/
STACK_OF(SCT) *scts;
/* Raw extension data, if seen */
unsigned char *tlsext_scts;
/* Length of raw extension data, if seen */
uint16_t tlsext_scts_len;
/* Have we attempted to find/parse SCTs yet? */
int scts_parsed;
# endif
/* Expect OCSP CertificateStatus message */
int tlsext_status_expected;
/* OCSP status request only */
STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids;
X509_EXTENSIONS *tlsext_ocsp_exts;
/* OCSP response received or to be sent */
unsigned char *tlsext_ocsp_resp;
int tlsext_ocsp_resplen;
/* RFC4507 session ticket expected to be received or sent */
int tlsext_ticket_expected;
# ifndef OPENSSL_NO_EC
size_t tlsext_ecpointformatlist_length;
/* our list */
unsigned char *tlsext_ecpointformatlist;
size_t tlsext_ellipticcurvelist_length;
/* our list */
unsigned char *tlsext_ellipticcurvelist;
# endif /* OPENSSL_NO_EC */
/* TLS Session Ticket extension override */
TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
/* TLS Session Ticket extension callback */
tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
void *tls_session_ticket_ext_cb_arg;
/* TLS pre-shared secret session resumption */
tls_session_secret_cb_fn tls_session_secret_cb;
void *tls_session_secret_cb_arg;
SSL_CTX *session_ctx; /* initial ctx, used to store sessions */
# ifndef OPENSSL_NO_NEXTPROTONEG
/*
* Next protocol negotiation. For the client, this is the protocol that
* we sent in NextProtocol and is set when handling ServerHello
* extensions. For a server, this is the client's selected_protocol from
* NextProtocol and is set when handling the NextProtocol message, before
* the Finished message.
*/
unsigned char *next_proto_negotiated;
unsigned char next_proto_negotiated_len;
# endif
/* What we'll do */
STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;
/* What's been chosen */
SRTP_PROTECTION_PROFILE *srtp_profile;
/*-
* Is use of the Heartbeat extension negotiated?
* 0: disabled
* 1: enabled
* 2: enabled, but not allowed to send Requests
*/
unsigned int tlsext_heartbeat;
/* Indicates if a HeartbeatRequest is in flight */
unsigned int tlsext_hb_pending;
/* HeartbeatRequest sequence number */
unsigned int tlsext_hb_seq;
/*
* For a client, this contains the list of supported protocols in wire
* format.
*/
unsigned char *alpn_client_proto_list;
unsigned alpn_client_proto_list_len;
/* Set to one if we have negotiated ETM */
int tlsext_use_etm;
/*-
* 1 if we are renegotiating.
* 2 if we are a server and are inside a handshake
* (i.e. not just sending a HelloRequest)
*/
int renegotiate;
# ifndef OPENSSL_NO_SRP
/* ctx for SRP authentication */
SRP_CTX srp_ctx;
# endif
/*
* Callback for disabling session caching and ticket support on a session
* basis, depending on the chosen cipher.
*/
int (*not_resumable_session_cb) (SSL *ssl, int is_forward_secure);
RECORD_LAYER rlayer;
/* Default password callback. */
pem_password_cb *default_passwd_callback;
/* Default password callback user data. */
void *default_passwd_callback_userdata;
/* Async Job info */
ASYNC_JOB *job;
ASYNC_WAIT_CTX *waitctx;
CRYPTO_RWLOCK *lock;
};
Upvotes: 0
Views: 1969
Reputation: 9392
The client callback looks like this:
typedef unsigned int (*SSL_psk_client_cb_func)(SSL *ssl,
const char *hint,
char *identity,
unsigned int max_identity_len,
unsigned char *psk,
unsigned int max_psk_len);
Your client side callback implementation is supposed to put the psk to use in the psk
buffer, as well as a NUL terminated identity
value in the identity
buffer. This identity is supposed to be unique to the PSK in use. If you have multiple clients each using a different PSK, then they should each have a different identity value.
On the server side the server callback gets passed the NUL terminated identity value that was supplied by the client. The server callback implementation is supposed to use that identity value to locate the correct PSK, and then fill in the psk
buffer with that value.
Upvotes: 1