Added CREDENTIAL frame support.
This commit is contained in:
parent
93953c102b
commit
d83d1cd33a
|
@ -34,13 +34,15 @@ lib_LTLIBRARIES = libspdylay.la
|
||||||
OBJECTS = spdylay_pq.c spdylay_map.c spdylay_queue.c \
|
OBJECTS = spdylay_pq.c spdylay_map.c spdylay_queue.c \
|
||||||
spdylay_buffer.c spdylay_frame.c spdylay_zlib.c \
|
spdylay_buffer.c spdylay_frame.c spdylay_zlib.c \
|
||||||
spdylay_session.c spdylay_helper.c spdylay_stream.c spdylay_npn.c \
|
spdylay_session.c spdylay_helper.c spdylay_stream.c spdylay_npn.c \
|
||||||
spdylay_submit.c spdylay_outbound_item.c
|
spdylay_submit.c spdylay_outbound_item.c \
|
||||||
|
spdylay_client_cert_vector.c
|
||||||
|
|
||||||
HFILES = spdylay_pq.h spdylay_int.h spdylay_map.h spdylay_queue.h \
|
HFILES = spdylay_pq.h spdylay_int.h spdylay_map.h spdylay_queue.h \
|
||||||
spdylay_buffer.h spdylay_frame.h spdylay_zlib.h \
|
spdylay_buffer.h spdylay_frame.h spdylay_zlib.h \
|
||||||
spdylay_session.h spdylay_helper.h spdylay_stream.h spdylay_int.h \
|
spdylay_session.h spdylay_helper.h spdylay_stream.h spdylay_int.h \
|
||||||
spdylay_npn.h \
|
spdylay_npn.h \
|
||||||
spdylay_submit.h spdylay_outbound_item.h \
|
spdylay_submit.h spdylay_outbound_item.h \
|
||||||
|
spdylay_client_cert_vector.h \
|
||||||
spdylay_net.h
|
spdylay_net.h
|
||||||
|
|
||||||
libspdylay_la_SOURCES = $(HFILES) $(OBJECTS)
|
libspdylay_la_SOURCES = $(HFILES) $(OBJECTS)
|
||||||
|
|
|
@ -154,6 +154,11 @@ typedef enum {
|
||||||
* multiple in-sequence NUL bytes).
|
* multiple in-sequence NUL bytes).
|
||||||
*/
|
*/
|
||||||
SPDYLAY_ERR_INVALID_HEADER_BLOCK = -518,
|
SPDYLAY_ERR_INVALID_HEADER_BLOCK = -518,
|
||||||
|
/**
|
||||||
|
* Indicates that the context is not suitable to perform the
|
||||||
|
* requested operation.
|
||||||
|
*/
|
||||||
|
SPDYLAY_ERR_INVALID_STATE = -519,
|
||||||
/**
|
/**
|
||||||
* The errors < :enum:`SPDYLAY_ERR_FATAL` mean that the library is
|
* The errors < :enum:`SPDYLAY_ERR_FATAL` mean that the library is
|
||||||
* under unexpected condition and cannot process any further data
|
* under unexpected condition and cannot process any further data
|
||||||
|
@ -214,7 +219,11 @@ typedef enum {
|
||||||
/**
|
/**
|
||||||
* The WINDOW_UPDATE control frame. This first appeared in SPDY/3.
|
* The WINDOW_UPDATE control frame. This first appeared in SPDY/3.
|
||||||
*/
|
*/
|
||||||
SPDYLAY_WINDOW_UPDATE = 9
|
SPDYLAY_WINDOW_UPDATE = 9,
|
||||||
|
/**
|
||||||
|
* The CREDENTIAL control frame. This first appeared in SPDY/3.
|
||||||
|
*/
|
||||||
|
SPDYLAY_CREDENTIAL = 10
|
||||||
} spdylay_frame_type;
|
} spdylay_frame_type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -635,6 +644,52 @@ typedef struct {
|
||||||
int32_t delta_window_size;
|
int32_t delta_window_size;
|
||||||
} spdylay_window_update;
|
} spdylay_window_update;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct
|
||||||
|
*
|
||||||
|
* The structure to hold chunk of memory.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* The pointer to the data.
|
||||||
|
*/
|
||||||
|
uint8_t *data;
|
||||||
|
/**
|
||||||
|
* The length of the data.
|
||||||
|
*/
|
||||||
|
size_t length;
|
||||||
|
} spdylay_mem_chunk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct
|
||||||
|
*
|
||||||
|
* The CREDENTIAL control frame. This first appeared in SPDY/3. It has
|
||||||
|
* the following members:
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* The control frame header.
|
||||||
|
*/
|
||||||
|
spdylay_ctrl_hd hd;
|
||||||
|
/**
|
||||||
|
* The index in the client certificate vector.
|
||||||
|
*/
|
||||||
|
uint16_t slot;
|
||||||
|
/**
|
||||||
|
* Cryptographic proof that the client has possession of the private
|
||||||
|
* key associated with the certificate.
|
||||||
|
*/
|
||||||
|
spdylay_mem_chunk proof;
|
||||||
|
/**
|
||||||
|
* The certificate chain. The certs[0] is the leaf certificate.
|
||||||
|
*/
|
||||||
|
spdylay_mem_chunk *certs;
|
||||||
|
/**
|
||||||
|
* The number of certificates in |certs|.
|
||||||
|
*/
|
||||||
|
size_t ncerts;
|
||||||
|
} spdylay_credential;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct
|
* @struct
|
||||||
*
|
*
|
||||||
|
@ -747,6 +802,10 @@ typedef union {
|
||||||
* The WINDOW_UPDATE control frame.
|
* The WINDOW_UPDATE control frame.
|
||||||
*/
|
*/
|
||||||
spdylay_window_update window_update;
|
spdylay_window_update window_update;
|
||||||
|
/**
|
||||||
|
* The CREDENTIAL control frame.
|
||||||
|
*/
|
||||||
|
spdylay_credential credential;
|
||||||
} spdylay_frame;
|
} spdylay_frame;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -895,54 +954,88 @@ typedef void (*spdylay_on_stream_close_callback)
|
||||||
typedef void (*spdylay_on_request_recv_callback)
|
typedef void (*spdylay_on_request_recv_callback)
|
||||||
(spdylay_session *session, int32_t stream_id, void *user_data);
|
(spdylay_session *session, int32_t stream_id, void *user_data);
|
||||||
|
|
||||||
|
#define SPDYLAY_MAX_SCHEME 255
|
||||||
|
#define SPDYLAY_MAX_HOSTNAME 255
|
||||||
|
|
||||||
|
struct spdylay_origin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct
|
||||||
|
*
|
||||||
|
* The Web origin structure. The origin is the tuple (scheme, host,
|
||||||
|
* port). The details of this structure is intentionally hidden. To
|
||||||
|
* access these members, use accessor functions below.
|
||||||
|
*/
|
||||||
|
typedef struct spdylay_origin spdylay_origin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Returns the scheme member of the |origin|.
|
||||||
|
*/
|
||||||
|
const char* spdylay_origin_get_scheme(const spdylay_origin *origin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Returns the host member of the |origin|.
|
||||||
|
*/
|
||||||
|
const char* spdylay_origin_get_host(const spdylay_origin *origin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Returns the port member of the |origin|.
|
||||||
|
*/
|
||||||
|
uint16_t spdylay_origin_get_port(const spdylay_origin *origin);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @functypedef
|
* @functypedef
|
||||||
*
|
*
|
||||||
* Callback function invoked when the library wants to know whether
|
* Callback function invoked when the library needs the cryptographic
|
||||||
* the client certificate is required for the given |origin| and if so
|
* proof that the client has possession of the private key associated
|
||||||
* requests the cryptographic proof for the certificate. The |origin|
|
* with the certificate for the given |origin|. If called with
|
||||||
* is the hostname and port number joined with ':' (e.g.,
|
* |prooflen| == 0, the implementation of this function must return
|
||||||
* example.org:8443). The implementation of this function must assign
|
* the length of the proof in bytes. If called with |prooflen| > 0,
|
||||||
* the pointer to the buffer where proof is stored to the |*proof_ptr|
|
* write proof into |proof| exactly |prooflen| bytes and return 0.
|
||||||
* and its length to the |*prooflen_ptr|. Return 0 if the function
|
|
||||||
* succeeds. If no client certificate is required for the |origin|,
|
|
||||||
* the function must return SPDYLAY_ERR_CLIENT_CERT_NOT_NEEDED.
|
|
||||||
* (TODO: add error code)
|
|
||||||
*
|
*
|
||||||
* The data stored in |*proof_ptr| will be copied just after the
|
* Because the client certificate vector has limited number of slots,
|
||||||
* function call. This copy lives until the CREDENTIAL frame is
|
* the application code may be required to pass the same proof more
|
||||||
* sent. Because the client certificate vector has limited number of
|
* than once.
|
||||||
* slots, the application code may be required to pass the same proof
|
|
||||||
* more than once.
|
|
||||||
*/
|
*/
|
||||||
typedef int (*spdylay_get_credential_proof)
|
typedef ssize_t (*spdylay_get_credential_proof)
|
||||||
(spdylay_session *session, const char *origin,
|
(spdylay_session *session, const spdylay_origin *origin,
|
||||||
uint8_t **proof_ptr, size_t *prooflen_ptr, void *user_data);
|
uint8_t *proof, size_t prooflen, void *user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @functypedef
|
||||||
|
*
|
||||||
|
* Callback function invoked when the library needs the length of the
|
||||||
|
* client certificate chain for the given |origin|. The
|
||||||
|
* implementation of this function must return the length of the
|
||||||
|
* client certificate chain. If no client certificate is required for
|
||||||
|
* the given |origin|, return 0. If positive integer is returned,
|
||||||
|
* :type:`spdylay_get_credential_proof` and
|
||||||
|
* :type:`spdylay_get_credential_cert` callback functions will be used
|
||||||
|
* to get the cryptographic proof and certificate respectively.
|
||||||
|
*/
|
||||||
|
typedef ssize_t (*spdylay_get_credential_ncerts)
|
||||||
|
(spdylay_session *session, const spdylay_origin *origin, void *user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @functypedef
|
* @functypedef
|
||||||
*
|
*
|
||||||
* Callback function invoked when the library needs the client
|
* Callback function invoked when the library needs the client
|
||||||
* certificate for the given |origin|. The |origin| is the hostname
|
* certificate for the given |origin|. The |index| is the index of the
|
||||||
* and port number joined with ':' (e.g., example.org:8443). The
|
* certificate chain and 0 means the leaf certificate of the chain.
|
||||||
* implementation of this function must assign the pointer to the
|
* If called with |certlen| == 0, the implementation of this function
|
||||||
* buffer where certificate is stored to the |*cert_ptr| and its
|
* must return the length of the certificate in bytes. If called with
|
||||||
* length to the |*certlen_ptr|. Because the library requires the
|
* |certlen| > 0, write certificate into |cert| exactly |certlen|
|
||||||
* certificate chain, this callback function will be called repeatedly
|
* bytes and return 0.
|
||||||
* to get certificate chain starting with the leaf certificate.
|
|
||||||
* Assign 0 to |*certlen_ptr| if there is no more
|
|
||||||
* certificate. Currently, the library does not expect for this
|
|
||||||
* function to fail. Therefore the function must return 0.
|
|
||||||
*
|
|
||||||
* The data stored in |*cert_ptr| will be copied just after the
|
|
||||||
* function call. This copy lives until the CREDENTIAL frame is
|
|
||||||
* sent. Because the client certificate vector has limited number of
|
|
||||||
* slots, the application code may be required to pass the same
|
|
||||||
* certificate more than once.
|
|
||||||
*/
|
*/
|
||||||
typedef int (*spdylay_get_credential_cert)
|
typedef ssize_t (*spdylay_get_credential_cert)
|
||||||
(spdylay_session *session, const char* origin,
|
(spdylay_session *session, const spdylay_origin *origin, size_t index,
|
||||||
uint8_t **cert_ptr, size_t *certlen_ptr, void *user_data);
|
uint8_t *cert, size_t certlen, void *user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct
|
* @struct
|
||||||
|
@ -1005,6 +1098,22 @@ typedef struct {
|
||||||
* received.
|
* received.
|
||||||
*/
|
*/
|
||||||
spdylay_on_request_recv_callback on_request_recv_callback;
|
spdylay_on_request_recv_callback on_request_recv_callback;
|
||||||
|
/**
|
||||||
|
* Callback function invoked when the library needs the
|
||||||
|
* cryptographic proof that the client has possession of the private
|
||||||
|
* key associated with the certificate.
|
||||||
|
*/
|
||||||
|
spdylay_get_credential_proof get_credential_proof;
|
||||||
|
/**
|
||||||
|
* Callback function invoked when the library needs the length of the
|
||||||
|
* client certificate chain.
|
||||||
|
*/
|
||||||
|
spdylay_get_credential_ncerts get_credential_ncerts;
|
||||||
|
/**
|
||||||
|
* Callback function invoked when the library needs the client
|
||||||
|
* certificate.
|
||||||
|
*/
|
||||||
|
spdylay_get_credential_cert get_credential_cert;
|
||||||
} spdylay_session_callbacks;
|
} spdylay_session_callbacks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1073,6 +1182,49 @@ int spdylay_session_server_new(spdylay_session **session_ptr,
|
||||||
*/
|
*/
|
||||||
void spdylay_session_del(spdylay_session *session);
|
void spdylay_session_del(spdylay_session *session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Sets the origin tuple (|scheme|, |host| and |port) that the
|
||||||
|
* connection is made to and the client certificate is sent in the
|
||||||
|
* first TLS handshake. This function must be called before any call
|
||||||
|
* of `spdylay_session_send()` and `spdylay_session_recv()` and be
|
||||||
|
* called only once per session. This function must not be called if
|
||||||
|
* the |session| is initialized for server use. If the client did not
|
||||||
|
* provide the client certificate in the first TLS handshake, this
|
||||||
|
* function must not be called.
|
||||||
|
*
|
||||||
|
* This function stores the given origin at the slot 1 in the client
|
||||||
|
* certificate vector.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* SPDYLAY_ERR_NOMEM
|
||||||
|
* Out of memory
|
||||||
|
* SPDYLAY_ERR_INVALID_STATE
|
||||||
|
* The |session| is initialized for server use; or the client
|
||||||
|
* certificate vector size is 0.
|
||||||
|
*/
|
||||||
|
int spdylay_session_set_initial_client_cert_origin(spdylay_session *session,
|
||||||
|
const char *scheme,
|
||||||
|
const char *host,
|
||||||
|
uint16_t port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Returns the origin at the index |slot| in the client certificate
|
||||||
|
* vector. If there is no origin at the given |slot|, this function
|
||||||
|
* returns ``NULL``.
|
||||||
|
*
|
||||||
|
* This function must not be called if the |session| is initialized
|
||||||
|
* for server use.
|
||||||
|
*/
|
||||||
|
const spdylay_origin* spdylay_session_get_client_cert_origin
|
||||||
|
(spdylay_session *session,
|
||||||
|
size_t slot);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
|
@ -1094,6 +1246,14 @@ void spdylay_session_del(spdylay_session *session);
|
||||||
* :member:`spdylay_session_callbacks.on_ctrl_not_send_callback` is
|
* :member:`spdylay_session_callbacks.on_ctrl_not_send_callback` is
|
||||||
* invoked. Abort the following steps.
|
* invoked. Abort the following steps.
|
||||||
* 4. If the frame is SYN_STREAM, the stream is opened here.
|
* 4. If the frame is SYN_STREAM, the stream is opened here.
|
||||||
|
* If the |session| is initialized for client use and the protocol
|
||||||
|
* version is :macro:`SPDYLAY_PROTO_SPDY3` and the library needs
|
||||||
|
* the client certificate for the origin,
|
||||||
|
* :member:`spdylay_session_callbacks.get_credential_ncerts` is
|
||||||
|
* invoked. If the result is more than zero,
|
||||||
|
* :member:`spdylay_session_callbacks.get_credential_proof` and
|
||||||
|
* :member:`spdylay_session_callbacks.get_credential_cert` are also
|
||||||
|
* invoked.
|
||||||
* 5. :member:`spdylay_session_callbacks.before_ctrl_send_callback` is
|
* 5. :member:`spdylay_session_callbacks.before_ctrl_send_callback` is
|
||||||
* invoked.
|
* invoked.
|
||||||
* 6. :member:`spdylay_session_callbacks.send_callback` is invoked one
|
* 6. :member:`spdylay_session_callbacks.send_callback` is invoked one
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "spdylay_client_cert_vector.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "spdylay_helper.h"
|
||||||
|
|
||||||
|
int spdylay_origin_equal(const spdylay_origin *lhs, const spdylay_origin *rhs)
|
||||||
|
{
|
||||||
|
return strcmp(lhs->scheme, rhs->scheme) == 0 &&
|
||||||
|
strcmp(lhs->host, rhs->host) == 0 && lhs->port == rhs->port;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_origin_set(spdylay_origin *origin,
|
||||||
|
const char *scheme, const char *host, uint16_t port)
|
||||||
|
{
|
||||||
|
if(strlen(scheme) > SPDYLAY_MAX_SCHEME ||
|
||||||
|
strlen(host) > SPDYLAY_MAX_HOSTNAME) {
|
||||||
|
return SPDYLAY_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
strcpy(origin->scheme, scheme);
|
||||||
|
strcpy(origin->host, host);
|
||||||
|
origin->port = port;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* spdylay_origin_get_scheme(const spdylay_origin *origin)
|
||||||
|
{
|
||||||
|
return origin->scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* spdylay_origin_get_host(const spdylay_origin *origin)
|
||||||
|
{
|
||||||
|
return origin->host;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t spdylay_origin_get_port(const spdylay_origin *origin)
|
||||||
|
{
|
||||||
|
return origin->port;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_client_cert_vector_init(spdylay_client_cert_vector *certvec,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
certvec->size = certvec->capacity = size;
|
||||||
|
certvec->last_slot = 0;
|
||||||
|
if(certvec->capacity) {
|
||||||
|
size_t size = sizeof(spdylay_origin*)*certvec->capacity;
|
||||||
|
certvec->vector = malloc(size);
|
||||||
|
if(certvec->vector == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
memset(certvec->vector, 0, size);
|
||||||
|
} else {
|
||||||
|
certvec->vector = NULL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_client_cert_vector_free(spdylay_client_cert_vector *certvec)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for(i = 0; i < certvec->size; ++i) {
|
||||||
|
free(certvec->vector[i]);
|
||||||
|
}
|
||||||
|
free(certvec->vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_client_cert_vector_resize(spdylay_client_cert_vector *certvec,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
if(certvec->capacity < size) {
|
||||||
|
spdylay_origin **vector = realloc(certvec->vector,
|
||||||
|
sizeof(spdylay_origin*)*size);
|
||||||
|
if(vector == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
memset(vector + certvec->capacity, 0,
|
||||||
|
sizeof(spdylay_origin*)*(size - certvec->capacity));
|
||||||
|
certvec->vector = vector;
|
||||||
|
certvec->size = certvec->capacity = size;
|
||||||
|
} else {
|
||||||
|
size_t i;
|
||||||
|
for(i = size; i < certvec->size; ++i) {
|
||||||
|
free(certvec->vector[i]);
|
||||||
|
certvec->vector[i] = NULL;
|
||||||
|
}
|
||||||
|
certvec->size = spdylay_min(certvec->size, size);
|
||||||
|
if(certvec->last_slot > certvec->size) {
|
||||||
|
certvec->last_slot = certvec->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t spdylay_client_cert_vector_find(spdylay_client_cert_vector *certvec,
|
||||||
|
const spdylay_origin *origin)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for(i = 0; i < certvec->size && certvec->vector[i]; ++i) {
|
||||||
|
if(spdylay_origin_equal(origin, certvec->vector[i])) {
|
||||||
|
return i+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t spdylay_client_cert_vector_put(spdylay_client_cert_vector *certvec,
|
||||||
|
spdylay_origin *origin)
|
||||||
|
{
|
||||||
|
if(certvec->size == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(certvec->last_slot == certvec->size) {
|
||||||
|
certvec->last_slot = 1;
|
||||||
|
} else {
|
||||||
|
++certvec->last_slot;
|
||||||
|
}
|
||||||
|
free(certvec->vector[certvec->last_slot-1]);
|
||||||
|
certvec->vector[certvec->last_slot-1] = origin;
|
||||||
|
return certvec->last_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
const spdylay_origin* spdylay_client_cert_vector_get_origin
|
||||||
|
(spdylay_client_cert_vector *certvec,
|
||||||
|
size_t slot)
|
||||||
|
{
|
||||||
|
if(slot == 0 || slot > certvec->size || !certvec->vector[slot-1]) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return certvec->vector[slot-1];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SPDYLAY_CLIENT_CERT_VECTOR_H
|
||||||
|
#define SPDYLAY_CLIENT_CERT_VECTOR_H
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include <spdylay/spdylay.h>
|
||||||
|
|
||||||
|
struct spdylay_origin {
|
||||||
|
char scheme[SPDYLAY_MAX_SCHEME+1];
|
||||||
|
char host[SPDYLAY_MAX_HOSTNAME+1];
|
||||||
|
uint16_t port;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
spdylay_origin **vector;
|
||||||
|
/* The size of the vector. */
|
||||||
|
size_t size;
|
||||||
|
/* The real capacity of the vector. size <= capacity holds true. */
|
||||||
|
size_t capacity;
|
||||||
|
/* The last slot where origin is stored. The default value is 0. */
|
||||||
|
size_t last_slot;
|
||||||
|
} spdylay_client_cert_vector;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns nonzero if |lhs| and |rhs| are equal. The equality is
|
||||||
|
* defined such that each member is equal respectively.
|
||||||
|
*/
|
||||||
|
int spdylay_origin_equal(const spdylay_origin *lhs, const spdylay_origin *rhs);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenient function to set members to the |origin|. The |origin|
|
||||||
|
* must be allocated prior this call.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* SPDYLAY_ERR_INVALID_ARGUMENT
|
||||||
|
* The |scheme| is longer than SPDYLAY_MAX_SCHEME; or the |host|
|
||||||
|
* is longer than SPDYLAY_MAX_HOSTNAME.
|
||||||
|
*/
|
||||||
|
int spdylay_origin_set(spdylay_origin *origin,
|
||||||
|
const char *scheme, const char *host, uint16_t port);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes the client certificate vector with the vector size
|
||||||
|
* |size|.
|
||||||
|
*/
|
||||||
|
int spdylay_client_cert_vector_init(spdylay_client_cert_vector *certvec,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
void spdylay_client_cert_vector_free(spdylay_client_cert_vector *certvec);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the slot of the |origin| in the client certificate vector.
|
||||||
|
* If it is not found, returns 0.
|
||||||
|
*/
|
||||||
|
size_t spdylay_client_cert_vector_find(spdylay_client_cert_vector *certvec,
|
||||||
|
const spdylay_origin *origin);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Puts the |origin| to the |certvec|. This function takes ownership
|
||||||
|
* of the |origin| on success.
|
||||||
|
*
|
||||||
|
* This function returns the positive slot index of the certificate
|
||||||
|
* vector where the |origin| is stored if it succeeds, or 0.
|
||||||
|
*/
|
||||||
|
size_t spdylay_client_cert_vector_put(spdylay_client_cert_vector *certvec,
|
||||||
|
spdylay_origin *origin);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resizes client certificate vector to the size |size|.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* SPDYLAY_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
|
*/
|
||||||
|
int spdylay_client_cert_vector_resize(spdylay_client_cert_vector *certvec,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
const spdylay_origin* spdylay_client_cert_vector_get_origin
|
||||||
|
(spdylay_client_cert_vector *certvec,
|
||||||
|
size_t slot);
|
||||||
|
|
||||||
|
#endif /* SPDYLAY_CLIENT_CERT_VECTOR_H */
|
|
@ -27,6 +27,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "spdylay_helper.h"
|
#include "spdylay_helper.h"
|
||||||
#include "spdylay_net.h"
|
#include "spdylay_net.h"
|
||||||
|
@ -500,6 +501,52 @@ void spdylay_frame_nv_2to3(char **nv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SPDYLAY_HTTPS_PORT 443
|
||||||
|
|
||||||
|
int spdylay_frame_nv_set_origin(char **nv, spdylay_origin *origin)
|
||||||
|
{
|
||||||
|
int scheme_found, host_found;
|
||||||
|
int i;
|
||||||
|
scheme_found = host_found = 0;
|
||||||
|
for(i = 0; nv[i]; i += 2) {
|
||||||
|
if(scheme_found == 0 && strcmp(":scheme", nv[i]) == 0) {
|
||||||
|
size_t len = strlen(nv[i+1]);
|
||||||
|
if(len <= SPDYLAY_MAX_SCHEME) {
|
||||||
|
strcpy(origin->scheme, nv[i+1]);
|
||||||
|
scheme_found = 1;
|
||||||
|
}
|
||||||
|
} else if(host_found == 0 && strcmp(":host", nv[i]) == 0) {
|
||||||
|
size_t len = strlen(nv[i+1]);
|
||||||
|
char *sep = memchr(nv[i+1], ':', len);
|
||||||
|
size_t hostlen;
|
||||||
|
if(sep == NULL) {
|
||||||
|
origin->port = SPDYLAY_HTTPS_PORT;
|
||||||
|
sep = nv[i+1]+len;
|
||||||
|
} else {
|
||||||
|
unsigned long int port;
|
||||||
|
errno = 0;
|
||||||
|
port = strtoul(sep+1, NULL, 10);
|
||||||
|
if(errno != 0 || port == 0 || port > UINT16_MAX) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
origin->port = port;
|
||||||
|
}
|
||||||
|
hostlen = sep-nv[i+1];
|
||||||
|
if(hostlen > SPDYLAY_MAX_HOSTNAME) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memcpy(origin->host, nv[i+1], hostlen);
|
||||||
|
origin->host[hostlen] = '\0';
|
||||||
|
host_found = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(scheme_found && host_found) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return SPDYLAY_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void spdylay_frame_syn_stream_init(spdylay_syn_stream *frame,
|
void spdylay_frame_syn_stream_init(spdylay_syn_stream *frame,
|
||||||
uint16_t version, uint8_t flags,
|
uint16_t version, uint8_t flags,
|
||||||
int32_t stream_id, int32_t assoc_stream_id,
|
int32_t stream_id, int32_t assoc_stream_id,
|
||||||
|
@ -640,6 +687,36 @@ void spdylay_frame_settings_free(spdylay_settings *frame)
|
||||||
free(frame->iv);
|
free(frame->iv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void spdylay_frame_credential_init(spdylay_credential *frame,
|
||||||
|
uint16_t version, uint16_t slot,
|
||||||
|
spdylay_mem_chunk *proof,
|
||||||
|
spdylay_mem_chunk *certs,
|
||||||
|
size_t ncerts)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
memset(frame, 0, sizeof(spdylay_credential));
|
||||||
|
frame->hd.version = version;
|
||||||
|
frame->hd.type = SPDYLAY_CREDENTIAL;
|
||||||
|
frame->slot = slot;
|
||||||
|
frame->proof = *proof;
|
||||||
|
frame->certs = certs;
|
||||||
|
frame->ncerts = ncerts;
|
||||||
|
frame->hd.length = 2+4+frame->proof.length;
|
||||||
|
for(i = 0; i < ncerts; ++i) {
|
||||||
|
frame->hd.length += 4+frame->certs[i].length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void spdylay_frame_credential_free(spdylay_credential *frame)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
free(frame->proof.data);
|
||||||
|
for(i = 0; i < frame->ncerts; ++i) {
|
||||||
|
free(frame->certs[i].data);
|
||||||
|
}
|
||||||
|
free(frame->certs);
|
||||||
|
}
|
||||||
|
|
||||||
void spdylay_frame_data_init(spdylay_data *frame, int32_t stream_id,
|
void spdylay_frame_data_init(spdylay_data *frame, int32_t stream_id,
|
||||||
uint8_t flags,
|
uint8_t flags,
|
||||||
const spdylay_data_provider *data_prd)
|
const spdylay_data_provider *data_prd)
|
||||||
|
@ -1076,6 +1153,158 @@ int spdylay_frame_unpack_settings(spdylay_settings *frame,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t spdylay_frame_pack_credential(uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||||
|
spdylay_credential *frame)
|
||||||
|
{
|
||||||
|
ssize_t framelen;
|
||||||
|
int r;
|
||||||
|
size_t i, offset;
|
||||||
|
framelen = SPDYLAY_FRAME_HEAD_LENGTH+2+4+frame->proof.length;
|
||||||
|
for(i = 0; i < frame->ncerts; ++i) {
|
||||||
|
framelen += 4+frame->certs[i].length;
|
||||||
|
}
|
||||||
|
r = spdylay_reserve_buffer(buf_ptr, buflen_ptr, framelen);
|
||||||
|
if(r != 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
memset(*buf_ptr, 0, framelen);
|
||||||
|
spdylay_frame_pack_ctrl_hd(*buf_ptr, &frame->hd);
|
||||||
|
offset = SPDYLAY_FRAME_HEAD_LENGTH;
|
||||||
|
spdylay_put_uint16be(&(*buf_ptr)[offset], frame->slot);
|
||||||
|
offset += 2;
|
||||||
|
spdylay_put_uint32be(&(*buf_ptr)[offset], frame->proof.length);
|
||||||
|
offset += 4;
|
||||||
|
memcpy(&(*buf_ptr)[offset], frame->proof.data, frame->proof.length);
|
||||||
|
offset += frame->proof.length;
|
||||||
|
for(i = 0; i < frame->ncerts; ++i) {
|
||||||
|
spdylay_put_uint32be(&(*buf_ptr)[offset], frame->certs[i].length);
|
||||||
|
offset += 4;
|
||||||
|
memcpy(&(*buf_ptr)[offset], frame->certs[i].data, frame->certs[i].length);
|
||||||
|
offset += frame->certs[i].length;
|
||||||
|
}
|
||||||
|
return framelen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Counts number of client certificate in CREDENTIAL frame payload
|
||||||
|
* |payload| with length |payloadlen|. The |payload| points to the
|
||||||
|
* length of the first certificate. This function also checks the
|
||||||
|
* frame payload is properly composed.
|
||||||
|
*
|
||||||
|
* This function returns the number of certificates in |payload| if it
|
||||||
|
* succeeds, or one of the following negative error codes:
|
||||||
|
*
|
||||||
|
* SPDYLAY_ERR_INVALID_FRAME
|
||||||
|
* The frame payload is invalid.
|
||||||
|
*/
|
||||||
|
static int spdylay_frame_count_unpack_cert(const uint8_t *payload,
|
||||||
|
size_t payloadlen)
|
||||||
|
{
|
||||||
|
size_t n, offset = 0;
|
||||||
|
for(n = 1; 1; ++n) {
|
||||||
|
size_t len;
|
||||||
|
if(offset+4 > payloadlen) {
|
||||||
|
return SPDYLAY_ERR_INVALID_FRAME;
|
||||||
|
}
|
||||||
|
len = spdylay_get_uint32(&payload[offset]);
|
||||||
|
offset += 4;
|
||||||
|
if(len > payloadlen || offset+len > payloadlen) {
|
||||||
|
return SPDYLAY_ERR_INVALID_FRAME;
|
||||||
|
} else {
|
||||||
|
offset += len;
|
||||||
|
if(offset == payloadlen) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unpacks client certificates in the |payload| with length
|
||||||
|
* |payloadlen|. First allocates memory to store the |ncerts|
|
||||||
|
* certificates. Stores certificates in the allocated space and set
|
||||||
|
* its pointer to |*certs_ptr|.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* SPDYLAY_ERR_NOMEM
|
||||||
|
* Out of memory
|
||||||
|
*/
|
||||||
|
static int spdylay_frame_unpack_cert(spdylay_mem_chunk **certs_ptr,
|
||||||
|
size_t ncerts,
|
||||||
|
const uint8_t *payload, size_t payloadlen)
|
||||||
|
{
|
||||||
|
size_t offset, i, j;
|
||||||
|
spdylay_mem_chunk *certs;
|
||||||
|
certs = malloc(sizeof(spdylay_mem_chunk)*ncerts);
|
||||||
|
if(certs == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
offset = 0;
|
||||||
|
for(i = 0; i < ncerts; ++i) {
|
||||||
|
certs[i].length = spdylay_get_uint32(&payload[offset]);
|
||||||
|
offset += 4;
|
||||||
|
certs[i].data = malloc(certs[i].length);
|
||||||
|
if(certs[i].data == NULL) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
memcpy(certs[i].data, &payload[offset], certs[i].length);
|
||||||
|
offset += certs[i].length;
|
||||||
|
}
|
||||||
|
*certs_ptr = certs;
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
for(j = 0; j < i; ++j) {
|
||||||
|
free(certs[j].data);
|
||||||
|
}
|
||||||
|
free(certs);
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_frame_unpack_credential(spdylay_credential *frame,
|
||||||
|
const uint8_t *head, size_t headlen,
|
||||||
|
const uint8_t *payload,
|
||||||
|
size_t payloadlen)
|
||||||
|
{
|
||||||
|
size_t offset;
|
||||||
|
int rv;
|
||||||
|
if(payloadlen < 10) {
|
||||||
|
return SPDYLAY_ERR_INVALID_FRAME;
|
||||||
|
}
|
||||||
|
spdylay_frame_unpack_ctrl_hd(&frame->hd, head);
|
||||||
|
offset = 0;
|
||||||
|
frame->slot = spdylay_get_uint16(&payload[offset]);
|
||||||
|
offset += 2;
|
||||||
|
frame->proof.length = spdylay_get_uint32(&payload[offset]);
|
||||||
|
offset += 4;
|
||||||
|
if(frame->proof.length > payloadlen ||
|
||||||
|
offset+frame->proof.length > payloadlen) {
|
||||||
|
return SPDYLAY_ERR_INVALID_FRAME;
|
||||||
|
}
|
||||||
|
frame->proof.data = malloc(frame->proof.length);
|
||||||
|
if(frame->proof.data == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
memcpy(frame->proof.data, &payload[offset], frame->proof.length);
|
||||||
|
offset += frame->proof.length;
|
||||||
|
rv = spdylay_frame_count_unpack_cert(payload+offset, payloadlen-offset);
|
||||||
|
if(rv < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
frame->ncerts = rv;
|
||||||
|
rv = spdylay_frame_unpack_cert(&frame->certs, frame->ncerts,
|
||||||
|
payload+offset, payloadlen-offset);
|
||||||
|
if(rv != 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
free(frame->proof.data);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
spdylay_settings_entry* spdylay_frame_iv_copy(const spdylay_settings_entry *iv,
|
spdylay_settings_entry* spdylay_frame_iv_copy(const spdylay_settings_entry *iv,
|
||||||
size_t niv)
|
size_t niv)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <spdylay/spdylay.h>
|
#include <spdylay/spdylay.h>
|
||||||
#include "spdylay_zlib.h"
|
#include "spdylay_zlib.h"
|
||||||
#include "spdylay_buffer.h"
|
#include "spdylay_buffer.h"
|
||||||
|
#include "spdylay_client_cert_vector.h"
|
||||||
|
|
||||||
#define SPDYLAY_STREAM_ID_MASK 0x7fffffff
|
#define SPDYLAY_STREAM_ID_MASK 0x7fffffff
|
||||||
#define SPDYLAY_LENGTH_MASK 0xffffff
|
#define SPDYLAY_LENGTH_MASK 0xffffff
|
||||||
|
@ -443,6 +444,35 @@ int spdylay_frame_unpack_settings(spdylay_settings *frame,
|
||||||
const uint8_t *head, size_t headlen,
|
const uint8_t *head, size_t headlen,
|
||||||
const uint8_t *payload, size_t payloadlen);
|
const uint8_t *payload, size_t payloadlen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packs CREDENTIAL frame |frame| in wire format and store it in
|
||||||
|
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
|
||||||
|
* length. This function expands |*buf_ptr| as necessary to store
|
||||||
|
* given |frame|.
|
||||||
|
*
|
||||||
|
* This function returns the size of packed frame if it succeeds, or
|
||||||
|
* returns one of the following negative error codes:
|
||||||
|
*
|
||||||
|
* SPDYLAY_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
|
*/
|
||||||
|
ssize_t spdylay_frame_pack_credential(uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||||
|
spdylay_credential *frame);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unpacks CREDENTIAL wire format into |frame|.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* SPDYLAY_ERR_INVALID_FRAME
|
||||||
|
* The input data are invalid.
|
||||||
|
* SPDYLAY_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
|
*/
|
||||||
|
int spdylay_frame_unpack_credential(spdylay_credential *frame,
|
||||||
|
const uint8_t *head, size_t headlen,
|
||||||
|
const uint8_t *payload, size_t payloadlen);
|
||||||
/*
|
/*
|
||||||
* Returns number of bytes to pack name/value pairs |nv|. This
|
* Returns number of bytes to pack name/value pairs |nv|. This
|
||||||
* function expects |nv| is sorted in ascending order of key.
|
* function expects |nv| is sorted in ascending order of key.
|
||||||
|
@ -661,6 +691,19 @@ void spdylay_frame_settings_init(spdylay_settings *frame,
|
||||||
|
|
||||||
void spdylay_frame_settings_free(spdylay_settings *frame);
|
void spdylay_frame_settings_free(spdylay_settings *frame);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes CREDENTIAL frame |frame| with given values. This
|
||||||
|
* function takes ownership of |proof->data| and |certs| on success.
|
||||||
|
* Note that the ownership of |proof| is not taken.
|
||||||
|
*/
|
||||||
|
void spdylay_frame_credential_init(spdylay_credential *frame,
|
||||||
|
uint16_t version, uint16_t slot,
|
||||||
|
spdylay_mem_chunk *proof,
|
||||||
|
spdylay_mem_chunk *certs,
|
||||||
|
size_t ncerts);
|
||||||
|
|
||||||
|
void spdylay_frame_credential_free(spdylay_credential *frame);
|
||||||
|
|
||||||
void spdylay_frame_data_init(spdylay_data *frame, int32_t stream_id,
|
void spdylay_frame_data_init(spdylay_data *frame, int32_t stream_id,
|
||||||
uint8_t flags,
|
uint8_t flags,
|
||||||
const spdylay_data_provider *data_prd);
|
const spdylay_data_provider *data_prd);
|
||||||
|
@ -716,6 +759,24 @@ void spdylay_frame_nv_3to2(char **nv);
|
||||||
*/
|
*/
|
||||||
void spdylay_frame_nv_2to3(char **nv);
|
void spdylay_frame_nv_2to3(char **nv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assigns the members of the |origin| using ":scheme" and ":host"
|
||||||
|
* values in |nv|.
|
||||||
|
*
|
||||||
|
* If ":host" value contains ':', this function parses the chracters
|
||||||
|
* after ':' as integer and uses it as port number.
|
||||||
|
*
|
||||||
|
* If ':' is missing in :host value, the default port number is used.
|
||||||
|
* The only defined default port number is 443.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error code:
|
||||||
|
*
|
||||||
|
* SPDYLAY_ERR_INVALID_ARGUMENT
|
||||||
|
* The |nv| lacks either :scheme or :host, or both.
|
||||||
|
*/
|
||||||
|
int spdylay_frame_nv_set_origin(char **nv, spdylay_origin *origin);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Makes copy of |iv| and return the copy. The |niv| is the number of
|
* Makes copy of |iv| and return the copy. The |niv| is the number of
|
||||||
* entries in |iv|. This function returns the pointer to the copy if
|
* entries in |iv|. This function returns the pointer to the copy if
|
||||||
|
|
|
@ -35,4 +35,10 @@
|
||||||
|
|
||||||
typedef int (*spdylay_compar)(const void *lhs, const void *rhs);
|
typedef int (*spdylay_compar)(const void *lhs, const void *rhs);
|
||||||
|
|
||||||
|
/* Internal error code. They must be in the range [-499, -100],
|
||||||
|
inclusive. */
|
||||||
|
typedef enum {
|
||||||
|
SPDYLAY_ERR_CREDENTIAL_PENDING = -100
|
||||||
|
} spdylay_internal_error;
|
||||||
|
|
||||||
#endif /* SPDYLAY_INT_H */
|
#endif /* SPDYLAY_INT_H */
|
||||||
|
|
|
@ -66,6 +66,9 @@ void spdylay_outbound_item_free(spdylay_outbound_item *item)
|
||||||
case SPDYLAY_WINDOW_UPDATE:
|
case SPDYLAY_WINDOW_UPDATE:
|
||||||
spdylay_frame_window_update_free(&frame->window_update);
|
spdylay_frame_window_update_free(&frame->window_update);
|
||||||
break;
|
break;
|
||||||
|
case SPDYLAY_CREDENTIAL:
|
||||||
|
spdylay_frame_credential_free(&frame->credential);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if(item->frame_cat == SPDYLAY_DATA) {
|
} else if(item->frame_cat == SPDYLAY_DATA) {
|
||||||
spdylay_data *data_frame;
|
spdylay_data *data_frame;
|
||||||
|
|
|
@ -32,6 +32,13 @@
|
||||||
#include <spdylay/spdylay.h>
|
#include <spdylay/spdylay.h>
|
||||||
#include "spdylay_frame.h"
|
#include "spdylay_frame.h"
|
||||||
|
|
||||||
|
/* Priority for PING */
|
||||||
|
#define SPDYLAY_OB_PRI_PING -10
|
||||||
|
/* Priority for CREDENTIAL */
|
||||||
|
#define SPDYLAY_OB_PRI_CREDENTIAL -2
|
||||||
|
/* Priority for the frame which must be sent after CREDENTIAL */
|
||||||
|
#define SPDYLAY_OB_PRI_AFTER_CREDENTIAL -1
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
spdylay_data_provider *data_prd;
|
spdylay_data_provider *data_prd;
|
||||||
void *stream_user_data;
|
void *stream_user_data;
|
||||||
|
|
|
@ -114,7 +114,8 @@ static void spdylay_inbound_frame_reset(spdylay_inbound_frame *iframe)
|
||||||
static int spdylay_session_new(spdylay_session **session_ptr,
|
static int spdylay_session_new(spdylay_session **session_ptr,
|
||||||
uint16_t version,
|
uint16_t version,
|
||||||
const spdylay_session_callbacks *callbacks,
|
const spdylay_session_callbacks *callbacks,
|
||||||
void *user_data)
|
void *user_data,
|
||||||
|
size_t cli_certvec_length)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
if(version != SPDYLAY_PROTO_SPDY2 && version != SPDYLAY_PROTO_SPDY3) {
|
if(version != SPDYLAY_PROTO_SPDY2 && version != SPDYLAY_PROTO_SPDY3) {
|
||||||
|
@ -205,8 +206,16 @@ static int spdylay_session_new(spdylay_session **session_ptr,
|
||||||
(*session_ptr)->iframe.bufmax = SPDYLAY_INITIAL_INBOUND_FRAMEBUF_LENGTH;
|
(*session_ptr)->iframe.bufmax = SPDYLAY_INITIAL_INBOUND_FRAMEBUF_LENGTH;
|
||||||
spdylay_inbound_frame_reset(&(*session_ptr)->iframe);
|
spdylay_inbound_frame_reset(&(*session_ptr)->iframe);
|
||||||
|
|
||||||
|
r = spdylay_client_cert_vector_init(&(*session_ptr)->cli_certvec,
|
||||||
|
cli_certvec_length);
|
||||||
|
if(r != 0) {
|
||||||
|
goto fail_client_cert_vector;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail_client_cert_vector:
|
||||||
|
free((*session_ptr)->iframe.buf);
|
||||||
fail_iframe_buf:
|
fail_iframe_buf:
|
||||||
free((*session_ptr)->nvbuf);
|
free((*session_ptr)->nvbuf);
|
||||||
fail_nvbuf:
|
fail_nvbuf:
|
||||||
|
@ -232,7 +241,8 @@ int spdylay_session_client_new(spdylay_session **session_ptr,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = spdylay_session_new(session_ptr, version, callbacks, user_data);
|
r = spdylay_session_new(session_ptr, version, callbacks, user_data,
|
||||||
|
SPDYLAY_INITIAL_CLIENT_CERT_VECTOR_LENGTH);
|
||||||
if(r == 0) {
|
if(r == 0) {
|
||||||
/* IDs for use in client */
|
/* IDs for use in client */
|
||||||
(*session_ptr)->next_stream_id = 1;
|
(*session_ptr)->next_stream_id = 1;
|
||||||
|
@ -248,7 +258,8 @@ int spdylay_session_server_new(spdylay_session **session_ptr,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = spdylay_session_new(session_ptr, version, callbacks, user_data);
|
r = spdylay_session_new(session_ptr, version, callbacks, user_data,
|
||||||
|
0);
|
||||||
if(r == 0) {
|
if(r == 0) {
|
||||||
(*session_ptr)->server = 1;
|
(*session_ptr)->server = 1;
|
||||||
/* IDs for use in client */
|
/* IDs for use in client */
|
||||||
|
@ -301,6 +312,7 @@ void spdylay_session_del(spdylay_session *session)
|
||||||
free(session->nvbuf);
|
free(session->nvbuf);
|
||||||
spdylay_buffer_free(&session->inflatebuf);
|
spdylay_buffer_free(&session->inflatebuf);
|
||||||
free(session->iframe.buf);
|
free(session->iframe.buf);
|
||||||
|
spdylay_client_cert_vector_free(&session->cli_certvec);
|
||||||
free(session);
|
free(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,8 +366,8 @@ int spdylay_session_add_frame(spdylay_session *session,
|
||||||
unreachable. */
|
unreachable. */
|
||||||
assert(0);
|
assert(0);
|
||||||
case SPDYLAY_PING:
|
case SPDYLAY_PING:
|
||||||
/* Ping has "height" priority. Give it -1. */
|
/* Ping has highest priority. */
|
||||||
item->pri = -1;
|
item->pri = SPDYLAY_OB_PRI_PING;
|
||||||
break;
|
break;
|
||||||
case SPDYLAY_GOAWAY:
|
case SPDYLAY_GOAWAY:
|
||||||
/* Should GOAWAY have higher priority? */
|
/* Should GOAWAY have higher priority? */
|
||||||
|
@ -376,6 +388,9 @@ int spdylay_session_add_frame(spdylay_session *session,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SPDYLAY_CREDENTIAL:
|
||||||
|
item->pri = SPDYLAY_OB_PRI_CREDENTIAL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if(frame_type == SPDYLAY_SYN_STREAM) {
|
if(frame_type == SPDYLAY_SYN_STREAM) {
|
||||||
r = spdylay_pq_push(&session->ob_ss_pq, item);
|
r = spdylay_pq_push(&session->ob_ss_pq, item);
|
||||||
|
@ -732,6 +747,146 @@ static int spdylay_session_predicate_data_send(spdylay_session *session,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieves cryptographic proof for the given |origin| using callback
|
||||||
|
* function and store it in |proof|.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* SPDYLAY_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
|
*/
|
||||||
|
static int spdylay_session_get_credential_proof(spdylay_session *session,
|
||||||
|
const spdylay_origin *origin,
|
||||||
|
spdylay_mem_chunk *proof)
|
||||||
|
{
|
||||||
|
proof->length = session->callbacks.get_credential_proof(session,
|
||||||
|
origin,
|
||||||
|
NULL, 0,
|
||||||
|
session->user_data);
|
||||||
|
proof->data = malloc(proof->length);
|
||||||
|
if(proof->data == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
session->callbacks.get_credential_proof(session, origin,
|
||||||
|
proof->data, proof->length,
|
||||||
|
session->user_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Retrieves client certificate chain for the given |origin| using
|
||||||
|
* callback functions and store the pointer to the allocated buffer
|
||||||
|
* containing certificate chain to |*certs_ptr|. The length of
|
||||||
|
* certificate chain is exactly |ncerts|.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* SPDYLAY_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
|
*/
|
||||||
|
static int spdylay_session_get_credential_cert(spdylay_session *session,
|
||||||
|
const spdylay_origin *origin,
|
||||||
|
spdylay_mem_chunk **certs_ptr,
|
||||||
|
size_t ncerts)
|
||||||
|
{
|
||||||
|
spdylay_mem_chunk *certs;
|
||||||
|
size_t i, j;
|
||||||
|
certs = malloc(sizeof(spdylay_mem_chunk)*ncerts);
|
||||||
|
if(certs == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
for(i = 0; i < ncerts; ++i) {
|
||||||
|
certs[i].length = session->callbacks.get_credential_cert
|
||||||
|
(session,
|
||||||
|
origin,
|
||||||
|
i, NULL, 0,
|
||||||
|
session->user_data);
|
||||||
|
certs[i].data = malloc(certs[i].length);
|
||||||
|
if(certs[i].data == NULL) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
session->callbacks.get_credential_cert(session, origin, i,
|
||||||
|
certs[i].data, certs[i].length,
|
||||||
|
session->user_data);
|
||||||
|
}
|
||||||
|
*certs_ptr = certs;
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
for(j = 0; j < i; ++j) {
|
||||||
|
free(certs[i].data);
|
||||||
|
}
|
||||||
|
free(certs);
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spdylay_session_prep_credential(spdylay_session *session,
|
||||||
|
spdylay_syn_stream *syn_stream)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
spdylay_origin origin;
|
||||||
|
spdylay_frame *frame;
|
||||||
|
spdylay_mem_chunk proof;
|
||||||
|
if(session->cli_certvec.size == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rv = spdylay_frame_nv_set_origin(syn_stream->nv, &origin);
|
||||||
|
if(rv == 0) {
|
||||||
|
size_t slot;
|
||||||
|
slot = spdylay_client_cert_vector_find(&session->cli_certvec, &origin);
|
||||||
|
if(slot == 0) {
|
||||||
|
ssize_t ncerts;
|
||||||
|
ncerts = session->callbacks.get_credential_ncerts(session, &origin,
|
||||||
|
session->user_data);
|
||||||
|
if(ncerts > 0) {
|
||||||
|
spdylay_mem_chunk *certs;
|
||||||
|
spdylay_origin *origin_copy;
|
||||||
|
frame = malloc(sizeof(spdylay_frame));
|
||||||
|
if(frame == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
origin_copy = malloc(sizeof(spdylay_origin));
|
||||||
|
if(origin_copy == NULL) {
|
||||||
|
goto fail_after_frame;
|
||||||
|
}
|
||||||
|
*origin_copy = origin;
|
||||||
|
slot = spdylay_client_cert_vector_put(&session->cli_certvec,
|
||||||
|
origin_copy);
|
||||||
|
|
||||||
|
rv = spdylay_session_get_credential_proof(session, &origin, &proof);
|
||||||
|
if(rv != 0) {
|
||||||
|
goto fail_after_frame;
|
||||||
|
}
|
||||||
|
rv = spdylay_session_get_credential_cert(session, &origin,
|
||||||
|
&certs, ncerts);
|
||||||
|
if(rv != 0) {
|
||||||
|
goto fail_after_proof;
|
||||||
|
}
|
||||||
|
spdylay_frame_credential_init(&frame->credential,
|
||||||
|
session->version,
|
||||||
|
slot, &proof, certs, ncerts);
|
||||||
|
rv = spdylay_session_add_frame(session, SPDYLAY_CTRL, frame, NULL);
|
||||||
|
if(rv != 0) {
|
||||||
|
spdylay_frame_credential_free(&frame->credential);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
return SPDYLAY_ERR_CREDENTIAL_PENDING;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
fail_after_proof:
|
||||||
|
free(proof.data);
|
||||||
|
fail_after_frame:
|
||||||
|
free(frame);
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
static ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
||||||
spdylay_outbound_item *item)
|
spdylay_outbound_item *item)
|
||||||
{
|
{
|
||||||
|
@ -751,8 +906,30 @@ static ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
||||||
if(r != 0) {
|
if(r != 0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
if(session->version == SPDYLAY_PROTO_SPDY3 &&
|
||||||
|
session->callbacks.get_credential_proof &&
|
||||||
|
session->callbacks.get_credential_cert &&
|
||||||
|
!session->server) {
|
||||||
|
int slot_index;
|
||||||
|
slot_index = spdylay_session_prep_credential(session,
|
||||||
|
&frame->syn_stream);
|
||||||
|
if(slot_index == SPDYLAY_ERR_CREDENTIAL_PENDING) {
|
||||||
|
/* CREDENTIAL frame has been queued. SYN_STREAM has to be
|
||||||
|
sent after that. Change the priority of this item to
|
||||||
|
achieve this. */
|
||||||
|
item->pri = SPDYLAY_OB_PRI_AFTER_CREDENTIAL;
|
||||||
|
r = spdylay_pq_push(&session->ob_ss_pq, item);
|
||||||
|
if(r == 0) {
|
||||||
|
return SPDYLAY_ERR_CREDENTIAL_PENDING;
|
||||||
|
} else {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
} else if(r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
frame->syn_stream.slot = slot_index;
|
||||||
|
}
|
||||||
stream_id = session->next_stream_id;
|
stream_id = session->next_stream_id;
|
||||||
|
|
||||||
frame->syn_stream.stream_id = stream_id;
|
frame->syn_stream.stream_id = stream_id;
|
||||||
session->next_stream_id += 2;
|
session->next_stream_id += 2;
|
||||||
if(session->version == SPDYLAY_PROTO_SPDY2) {
|
if(session->version == SPDYLAY_PROTO_SPDY2) {
|
||||||
|
@ -892,6 +1069,15 @@ static ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
||||||
return framebuflen;
|
return framebuflen;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SPDYLAY_CREDENTIAL: {
|
||||||
|
framebuflen = spdylay_frame_pack_credential(&session->aob.framebuf,
|
||||||
|
&session->aob.framebufmax,
|
||||||
|
&frame->credential);
|
||||||
|
if(framebuflen < 0) {
|
||||||
|
return framebuflen;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
framebuflen = SPDYLAY_ERR_INVALID_ARGUMENT;
|
framebuflen = SPDYLAY_ERR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
@ -1134,6 +1320,8 @@ static int spdylay_session_after_frame_sent(spdylay_session *session)
|
||||||
}
|
}
|
||||||
case SPDYLAY_WINDOW_UPDATE:
|
case SPDYLAY_WINDOW_UPDATE:
|
||||||
break;
|
break;
|
||||||
|
case SPDYLAY_CREDENTIAL:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
spdylay_active_outbound_item_reset(&session->aob);
|
spdylay_active_outbound_item_reset(&session->aob);
|
||||||
} else if(item->frame_cat == SPDYLAY_DATA) {
|
} else if(item->frame_cat == SPDYLAY_DATA) {
|
||||||
|
@ -1235,7 +1423,8 @@ int spdylay_session_send(spdylay_session *session)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
framebuflen = spdylay_session_prep_frame(session, item);
|
framebuflen = spdylay_session_prep_frame(session, item);
|
||||||
if(framebuflen == SPDYLAY_ERR_DEFERRED) {
|
if(framebuflen == SPDYLAY_ERR_DEFERRED ||
|
||||||
|
framebuflen == SPDYLAY_ERR_CREDENTIAL_PENDING) {
|
||||||
continue;
|
continue;
|
||||||
} else if(framebuflen < 0) {
|
} else if(framebuflen < 0) {
|
||||||
if(item->frame_cat == SPDYLAY_CTRL &&
|
if(item->frame_cat == SPDYLAY_CTRL &&
|
||||||
|
@ -1624,7 +1813,7 @@ int spdylay_session_on_settings_received(spdylay_session *session,
|
||||||
/* Check ID/value pairs and persist them if necessary. */
|
/* Check ID/value pairs and persist them if necessary. */
|
||||||
memset(check, 0, sizeof(check));
|
memset(check, 0, sizeof(check));
|
||||||
for(i = 0; i < frame->settings.niv; ++i) {
|
for(i = 0; i < frame->settings.niv; ++i) {
|
||||||
const spdylay_settings_entry *entry = &frame->settings.iv[i];
|
spdylay_settings_entry *entry = &frame->settings.iv[i];
|
||||||
/* SPDY/3 spec says if the multiple values for the same ID were
|
/* SPDY/3 spec says if the multiple values for the same ID were
|
||||||
found, use the first one and ignore the rest. */
|
found, use the first one and ignore the rest. */
|
||||||
if(entry->settings_id > SPDYLAY_SETTINGS_MAX || entry->settings_id == 0 ||
|
if(entry->settings_id > SPDYLAY_SETTINGS_MAX || entry->settings_id == 0 ||
|
||||||
|
@ -1639,6 +1828,19 @@ int spdylay_session_on_settings_received(spdylay_session *session,
|
||||||
if(entry->value < (1u << 31)) {
|
if(entry->value < (1u << 31)) {
|
||||||
spdylay_session_update_initial_window_size(session, entry->value);
|
spdylay_session_update_initial_window_size(session, entry->value);
|
||||||
}
|
}
|
||||||
|
} else if(entry->settings_id ==
|
||||||
|
SPDYLAY_SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE) {
|
||||||
|
if(!session->server) {
|
||||||
|
int rv;
|
||||||
|
/* Limit certificate vector length in the reasonable size. */
|
||||||
|
entry->value = spdylay_min(entry->value,
|
||||||
|
SPDYLAY_MAX_CLIENT_CERT_VECTOR_LENGTH);
|
||||||
|
rv = spdylay_client_cert_vector_resize(&session->cli_certvec,
|
||||||
|
entry->value);
|
||||||
|
if(rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
session->remote_settings[entry->settings_id] = entry->value;
|
session->remote_settings[entry->settings_id] = entry->value;
|
||||||
}
|
}
|
||||||
|
@ -1721,6 +1923,19 @@ int spdylay_session_on_window_update_received(spdylay_session *session,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int spdylay_session_on_credential_received(spdylay_session *session,
|
||||||
|
spdylay_frame *frame)
|
||||||
|
{
|
||||||
|
if(!spdylay_session_check_version(session, frame->credential.hd.version)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* We don't care about the body of the CREDENTIAL frame. It is left
|
||||||
|
to the application code to decide it is invalid or not. */
|
||||||
|
spdylay_session_call_on_ctrl_frame_received(session, SPDYLAY_CREDENTIAL,
|
||||||
|
frame);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int spdylay_session_on_headers_received(spdylay_session *session,
|
int spdylay_session_on_headers_received(spdylay_session *session,
|
||||||
spdylay_frame *frame)
|
spdylay_frame *frame)
|
||||||
{
|
{
|
||||||
|
@ -1930,6 +2145,19 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
|
||||||
r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
|
r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SPDYLAY_CREDENTIAL:
|
||||||
|
r = spdylay_frame_unpack_credential(&frame.credential,
|
||||||
|
session->iframe.headbuf,
|
||||||
|
sizeof(session->iframe.headbuf),
|
||||||
|
session->iframe.buf,
|
||||||
|
session->iframe.len);
|
||||||
|
if(r == 0) {
|
||||||
|
r = spdylay_session_on_credential_received(session, &frame);
|
||||||
|
spdylay_frame_credential_free(&frame.credential);
|
||||||
|
} else if(spdylay_is_non_fatal(r)) {
|
||||||
|
r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if(spdylay_is_fatal(r)) {
|
if(spdylay_is_fatal(r)) {
|
||||||
return r;
|
return r;
|
||||||
|
@ -2360,3 +2588,38 @@ size_t spdylay_session_get_outbound_queue_size(spdylay_session *session)
|
||||||
{
|
{
|
||||||
return spdylay_pq_size(&session->ob_pq)+spdylay_pq_size(&session->ob_ss_pq);
|
return spdylay_pq_size(&session->ob_pq)+spdylay_pq_size(&session->ob_ss_pq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int spdylay_session_set_initial_client_cert_origin(spdylay_session *session,
|
||||||
|
const char *scheme,
|
||||||
|
const char *host,
|
||||||
|
uint16_t port)
|
||||||
|
{
|
||||||
|
spdylay_origin *origin;
|
||||||
|
size_t slot;
|
||||||
|
if(strlen(scheme) > SPDYLAY_MAX_SCHEME ||
|
||||||
|
strlen(host) > SPDYLAY_MAX_HOSTNAME) {
|
||||||
|
return SPDYLAY_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
if(session->server ||
|
||||||
|
(session->cli_certvec.size == 0 ||
|
||||||
|
session->cli_certvec.last_slot != 0)) {
|
||||||
|
return SPDYLAY_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
origin = malloc(sizeof(spdylay_origin));
|
||||||
|
if(origin == NULL) {
|
||||||
|
return SPDYLAY_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
strcpy(origin->scheme, scheme);
|
||||||
|
strcpy(origin->host, host);
|
||||||
|
origin->port = port;
|
||||||
|
slot = spdylay_client_cert_vector_put(&session->cli_certvec, origin);
|
||||||
|
assert(slot == 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const spdylay_origin* spdylay_session_get_client_cert_origin
|
||||||
|
(spdylay_session *session,
|
||||||
|
size_t slot)
|
||||||
|
{
|
||||||
|
return spdylay_client_cert_vector_get_origin(&session->cli_certvec, slot);
|
||||||
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "spdylay_stream.h"
|
#include "spdylay_stream.h"
|
||||||
#include "spdylay_buffer.h"
|
#include "spdylay_buffer.h"
|
||||||
#include "spdylay_outbound_item.h"
|
#include "spdylay_outbound_item.h"
|
||||||
|
#include "spdylay_client_cert_vector.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @macro
|
* @macro
|
||||||
|
@ -74,6 +75,11 @@ typedef struct {
|
||||||
|
|
||||||
#define SPDYLAY_INITIAL_WINDOW_SIZE 65536
|
#define SPDYLAY_INITIAL_WINDOW_SIZE 65536
|
||||||
|
|
||||||
|
/* Initial size of client certificate vector */
|
||||||
|
#define SPDYLAY_INITIAL_CLIENT_CERT_VECTOR_LENGTH 8
|
||||||
|
/* Maxmum size of client certificate vector */
|
||||||
|
#define SPDYLAY_MAX_CLIENT_CERT_VECTOR_LENGTH 255
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SPDYLAY_RECV_HEAD,
|
SPDYLAY_RECV_HEAD,
|
||||||
SPDYLAY_RECV_PAYLOAD
|
SPDYLAY_RECV_PAYLOAD
|
||||||
|
@ -167,6 +173,9 @@ struct spdylay_session {
|
||||||
/* Settings value of the local endpoint. */
|
/* Settings value of the local endpoint. */
|
||||||
uint32_t local_settings[SPDYLAY_SETTINGS_MAX+1];
|
uint32_t local_settings[SPDYLAY_SETTINGS_MAX+1];
|
||||||
|
|
||||||
|
/* Client certificate vector */
|
||||||
|
spdylay_client_cert_vector cli_certvec;
|
||||||
|
|
||||||
spdylay_session_callbacks callbacks;
|
spdylay_session_callbacks callbacks;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
@ -411,6 +420,15 @@ int spdylay_session_on_headers_received(spdylay_session *session,
|
||||||
int spdylay_session_on_window_update_received(spdylay_session *session,
|
int spdylay_session_on_window_update_received(spdylay_session *session,
|
||||||
spdylay_frame *frame);
|
spdylay_frame *frame);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when CREDENTIAL is received, assuming |frame.credential| is
|
||||||
|
* properly initialized.
|
||||||
|
*
|
||||||
|
* Currently, this function always succeeds and returns 0.
|
||||||
|
*/
|
||||||
|
int spdylay_session_on_credential_received(spdylay_session *session,
|
||||||
|
spdylay_frame *frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when DATA is received.
|
* Called when DATA is received.
|
||||||
*
|
*
|
||||||
|
@ -495,4 +513,21 @@ void spdylay_session_update_local_settings(spdylay_session *session,
|
||||||
spdylay_settings_entry *iv,
|
spdylay_settings_entry *iv,
|
||||||
size_t niv);
|
size_t niv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the index in the client certificate vector for the
|
||||||
|
* |syn_stream|. The origin is computed from |syn_stream->nv|. If no
|
||||||
|
* client certificate is required, return 0. If CREDENTIAL frame needs
|
||||||
|
* to be sent before the |syn_stream|, this function returns
|
||||||
|
* :macro:`SPDYLAY_ERR_CREDENTIAL_PENDING`. In this case, CREDENTIAL
|
||||||
|
* frame has been already queued. This function returns one of the
|
||||||
|
* following negative error codes:
|
||||||
|
*
|
||||||
|
* SPDYLAY_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
|
* SPDYLAY_ERR_CREDENTIAL_PENDING
|
||||||
|
* The CREDENTIAL frame must be sent before the |syn_stream|.
|
||||||
|
*/
|
||||||
|
int spdylay_session_prep_credential(spdylay_session *session,
|
||||||
|
spdylay_syn_stream *syn_stream);
|
||||||
|
|
||||||
#endif /* SPDYLAY_SESSION_H */
|
#endif /* SPDYLAY_SESSION_H */
|
||||||
|
|
|
@ -27,11 +27,13 @@ check_PROGRAMS = main
|
||||||
|
|
||||||
OBJECTS = main.c spdylay_pq_test.c spdylay_map_test.c spdylay_queue_test.c \
|
OBJECTS = main.c spdylay_pq_test.c spdylay_map_test.c spdylay_queue_test.c \
|
||||||
spdylay_buffer_test.c spdylay_zlib_test.c spdylay_session_test.c \
|
spdylay_buffer_test.c spdylay_zlib_test.c spdylay_session_test.c \
|
||||||
spdylay_frame_test.c spdylay_stream_test.c spdylay_npn_test.c
|
spdylay_frame_test.c spdylay_stream_test.c spdylay_npn_test.c \
|
||||||
|
spdylay_client_cert_vector_test.c
|
||||||
|
|
||||||
HFILES = spdylay_pq_test.h spdylay_map_test.h spdylay_queue_test.h \
|
HFILES = spdylay_pq_test.h spdylay_map_test.h spdylay_queue_test.h \
|
||||||
spdylay_buffer_test.h spdylay_zlib_test.h spdylay_session_test.h \
|
spdylay_buffer_test.h spdylay_zlib_test.h spdylay_session_test.h \
|
||||||
spdylay_frame_test.h spdylay_stream_test.h spdylay_npn_test.h
|
spdylay_frame_test.h spdylay_stream_test.h spdylay_npn_test.h \
|
||||||
|
spdylay_client_cert_vector_test.h
|
||||||
|
|
||||||
main_SOURCES = $(HFILES) $(OBJECTS)
|
main_SOURCES = $(HFILES) $(OBJECTS)
|
||||||
|
|
||||||
|
|
19
tests/main.c
19
tests/main.c
|
@ -35,6 +35,7 @@
|
||||||
#include "spdylay_frame_test.h"
|
#include "spdylay_frame_test.h"
|
||||||
#include "spdylay_stream_test.h"
|
#include "spdylay_stream_test.h"
|
||||||
#include "spdylay_npn_test.h"
|
#include "spdylay_npn_test.h"
|
||||||
|
#include "spdylay_client_cert_vector_test.h"
|
||||||
|
|
||||||
static int init_suite1(void)
|
static int init_suite1(void)
|
||||||
{
|
{
|
||||||
|
@ -144,6 +145,12 @@ int main(int argc, char* argv[])
|
||||||
test_spdylay_submit_settings) ||
|
test_spdylay_submit_settings) ||
|
||||||
!CU_add_test(pSuite, "session_get_outbound_queue_size",
|
!CU_add_test(pSuite, "session_get_outbound_queue_size",
|
||||||
test_spdylay_session_get_outbound_queue_size) ||
|
test_spdylay_session_get_outbound_queue_size) ||
|
||||||
|
!CU_add_test(pSuite, "session_prep_credential",
|
||||||
|
test_spdylay_session_prep_credential) ||
|
||||||
|
!CU_add_test(pSuite, "session_submit_syn_stream_with_credential",
|
||||||
|
test_spdylay_submit_syn_stream_with_credential) ||
|
||||||
|
!CU_add_test(pSuite, "session_set_initial_client_cert_origin",
|
||||||
|
test_spdylay_session_set_initial_client_cert_origin) ||
|
||||||
!CU_add_test(pSuite, "frame_unpack_nv_spdy2",
|
!CU_add_test(pSuite, "frame_unpack_nv_spdy2",
|
||||||
test_spdylay_frame_unpack_nv_spdy2) ||
|
test_spdylay_frame_unpack_nv_spdy2) ||
|
||||||
!CU_add_test(pSuite, "frame_unpack_nv_spdy3",
|
!CU_add_test(pSuite, "frame_unpack_nv_spdy3",
|
||||||
|
@ -175,6 +182,8 @@ int main(int argc, char* argv[])
|
||||||
test_spdylay_frame_pack_settings_spdy2) ||
|
test_spdylay_frame_pack_settings_spdy2) ||
|
||||||
!CU_add_test(pSuite, "frame_pack_settings_spdy3",
|
!CU_add_test(pSuite, "frame_pack_settings_spdy3",
|
||||||
test_spdylay_frame_pack_settings_spdy3) ||
|
test_spdylay_frame_pack_settings_spdy3) ||
|
||||||
|
!CU_add_test(pSuite, "frame_pack_credential",
|
||||||
|
test_spdylay_frame_pack_credential) ||
|
||||||
!CU_add_test(pSuite, "frame_nv_sort", test_spdylay_frame_nv_sort) ||
|
!CU_add_test(pSuite, "frame_nv_sort", test_spdylay_frame_nv_sort) ||
|
||||||
!CU_add_test(pSuite, "frame_nv_downcase",
|
!CU_add_test(pSuite, "frame_nv_downcase",
|
||||||
test_spdylay_frame_nv_downcase) ||
|
test_spdylay_frame_nv_downcase) ||
|
||||||
|
@ -186,8 +195,16 @@ int main(int argc, char* argv[])
|
||||||
test_spdylay_frame_unpack_nv_check_name_spdy2) ||
|
test_spdylay_frame_unpack_nv_check_name_spdy2) ||
|
||||||
!CU_add_test(pSuite, "frame_unpack_nv_check_name_spdy3",
|
!CU_add_test(pSuite, "frame_unpack_nv_check_name_spdy3",
|
||||||
test_spdylay_frame_unpack_nv_check_name_spdy3) ||
|
test_spdylay_frame_unpack_nv_check_name_spdy3) ||
|
||||||
|
!CU_add_test(pSuite, "frame_nv_set_origin",
|
||||||
|
test_spdylay_frame_nv_set_origin) ||
|
||||||
!CU_add_test(pSuite, "stream_add_pushed_stream",
|
!CU_add_test(pSuite, "stream_add_pushed_stream",
|
||||||
test_spdylay_stream_add_pushed_stream)) {
|
test_spdylay_stream_add_pushed_stream) ||
|
||||||
|
!CU_add_test(pSuite, "client_cert_vector_find",
|
||||||
|
test_spdylay_client_cert_vector_find) ||
|
||||||
|
!CU_add_test(pSuite, "client_cert_vector_resize",
|
||||||
|
test_spdylay_client_cert_vector_resize) ||
|
||||||
|
!CU_add_test(pSuite, "client_cert_vector_get_origin",
|
||||||
|
test_spdylay_client_cert_vector_get_origin)) {
|
||||||
CU_cleanup_registry();
|
CU_cleanup_registry();
|
||||||
return CU_get_error();
|
return CU_get_error();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "spdylay_client_cert_vector_test.h"
|
||||||
|
|
||||||
|
#include <CUnit/CUnit.h>
|
||||||
|
|
||||||
|
#include "spdylay_client_cert_vector.h"
|
||||||
|
|
||||||
|
static spdylay_origin* create_origin(const char *scheme, const char *host,
|
||||||
|
uint16_t port)
|
||||||
|
{
|
||||||
|
spdylay_origin *origin = malloc(sizeof(spdylay_origin));
|
||||||
|
spdylay_origin_set(origin, scheme, host, port);
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_spdylay_client_cert_vector_find(void)
|
||||||
|
{
|
||||||
|
spdylay_client_cert_vector certvec;
|
||||||
|
spdylay_origin *origin;
|
||||||
|
const spdylay_origin *origin_get;
|
||||||
|
size_t slot;
|
||||||
|
spdylay_client_cert_vector_init(&certvec, 3);
|
||||||
|
|
||||||
|
origin = create_origin("https", "example.org", 443);
|
||||||
|
CU_ASSERT(0 == spdylay_client_cert_vector_find(&certvec, origin));
|
||||||
|
CU_ASSERT(1 == spdylay_client_cert_vector_put(&certvec, origin));
|
||||||
|
slot = spdylay_client_cert_vector_find(&certvec, origin);
|
||||||
|
CU_ASSERT(1 == slot);
|
||||||
|
origin_get = spdylay_client_cert_vector_get_origin(&certvec, slot);
|
||||||
|
CU_ASSERT(strcmp(origin->scheme, origin_get->scheme) == 0);
|
||||||
|
CU_ASSERT(strcmp(origin->host, origin_get->host) == 0);
|
||||||
|
CU_ASSERT(origin->port == origin_get->port);
|
||||||
|
|
||||||
|
origin = create_origin("https", "example.org", 8443);
|
||||||
|
CU_ASSERT(0 == spdylay_client_cert_vector_find(&certvec, origin));
|
||||||
|
CU_ASSERT(2 == spdylay_client_cert_vector_put(&certvec, origin));
|
||||||
|
slot = spdylay_client_cert_vector_find(&certvec, origin);
|
||||||
|
CU_ASSERT(2 == slot);
|
||||||
|
|
||||||
|
origin = create_origin("https", "example.com", 443);
|
||||||
|
CU_ASSERT(0 == spdylay_client_cert_vector_find(&certvec, origin));
|
||||||
|
CU_ASSERT(3 == spdylay_client_cert_vector_put(&certvec, origin));
|
||||||
|
slot = spdylay_client_cert_vector_find(&certvec, origin);
|
||||||
|
CU_ASSERT(3 == slot);
|
||||||
|
|
||||||
|
origin = create_origin("https", "example.com", 8443);
|
||||||
|
CU_ASSERT(0 == spdylay_client_cert_vector_find(&certvec, origin));
|
||||||
|
CU_ASSERT(1 == spdylay_client_cert_vector_put(&certvec, origin));
|
||||||
|
slot = spdylay_client_cert_vector_find(&certvec, origin);
|
||||||
|
CU_ASSERT(1 == slot);
|
||||||
|
|
||||||
|
origin = create_origin("https", "example.org", 443);
|
||||||
|
CU_ASSERT(0 == spdylay_client_cert_vector_find(&certvec, origin));
|
||||||
|
free(origin);
|
||||||
|
|
||||||
|
spdylay_client_cert_vector_free(&certvec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_spdylay_client_cert_vector_resize(void)
|
||||||
|
{
|
||||||
|
spdylay_client_cert_vector certvec;
|
||||||
|
spdylay_origin *origin;
|
||||||
|
size_t i;
|
||||||
|
spdylay_client_cert_vector_init(&certvec, 3);
|
||||||
|
|
||||||
|
origin = create_origin("https", "example.org", 443);
|
||||||
|
spdylay_client_cert_vector_put(&certvec, origin);
|
||||||
|
origin = create_origin("https", "example.com", 443);
|
||||||
|
spdylay_client_cert_vector_put(&certvec, origin);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == spdylay_client_cert_vector_resize(&certvec, 1));
|
||||||
|
CU_ASSERT(NULL != spdylay_client_cert_vector_get_origin(&certvec, 1));
|
||||||
|
CU_ASSERT(1 == certvec.last_slot);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == spdylay_client_cert_vector_resize(&certvec, 8));
|
||||||
|
CU_ASSERT(NULL != spdylay_client_cert_vector_get_origin(&certvec, 1));
|
||||||
|
CU_ASSERT(1 == certvec.last_slot);
|
||||||
|
for(i = 2; i <= 8; ++i) {
|
||||||
|
CU_ASSERT(NULL == spdylay_client_cert_vector_get_origin(&certvec, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
spdylay_client_cert_vector_free(&certvec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_spdylay_client_cert_vector_get_origin(void)
|
||||||
|
{
|
||||||
|
spdylay_client_cert_vector certvec;
|
||||||
|
spdylay_origin *origin;
|
||||||
|
spdylay_client_cert_vector_init(&certvec, 3);
|
||||||
|
|
||||||
|
origin = create_origin("https", "example.org", 443);
|
||||||
|
CU_ASSERT(1 == spdylay_client_cert_vector_put(&certvec, origin));
|
||||||
|
|
||||||
|
CU_ASSERT(NULL == spdylay_client_cert_vector_get_origin(&certvec, 0));
|
||||||
|
CU_ASSERT(NULL != spdylay_client_cert_vector_get_origin(&certvec, 1));
|
||||||
|
CU_ASSERT(NULL == spdylay_client_cert_vector_get_origin(&certvec, 2));
|
||||||
|
CU_ASSERT(NULL == spdylay_client_cert_vector_get_origin(&certvec, 3));
|
||||||
|
CU_ASSERT(NULL == spdylay_client_cert_vector_get_origin(&certvec, 4));
|
||||||
|
|
||||||
|
spdylay_client_cert_vector_free(&certvec);
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Spdylay - SPDY Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef SPDYLAY_CLIENT_CERT_VECTOR_TEST_H
|
||||||
|
#define SPDYLAY_CLIENT_CERT_VECTOR_TEST_H
|
||||||
|
|
||||||
|
void test_spdylay_client_cert_vector_find(void);
|
||||||
|
void test_spdylay_client_cert_vector_resize(void);
|
||||||
|
void test_spdylay_client_cert_vector_get_origin(void);
|
||||||
|
|
||||||
|
#endif /* SPDYLAY_CLIENT_CERT_VECTOR_TEST_H */
|
|
@ -517,6 +517,66 @@ void test_spdylay_frame_pack_settings_spdy3(void)
|
||||||
test_spdylay_frame_pack_settings_version(SPDYLAY_PROTO_SPDY3);
|
test_spdylay_frame_pack_settings_version(SPDYLAY_PROTO_SPDY3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char* strcopy(const char* s)
|
||||||
|
{
|
||||||
|
size_t len = strlen(s);
|
||||||
|
char *dest = malloc(len+1);
|
||||||
|
memcpy(dest, s, len);
|
||||||
|
dest[len] = '\0';
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_spdylay_frame_pack_credential(void)
|
||||||
|
{
|
||||||
|
spdylay_frame frame, oframe;
|
||||||
|
uint8_t *buf = NULL;
|
||||||
|
size_t buflen = 0;
|
||||||
|
ssize_t framelen;
|
||||||
|
spdylay_mem_chunk proof;
|
||||||
|
spdylay_mem_chunk *certs;
|
||||||
|
size_t ncerts;
|
||||||
|
proof.data = (uint8_t*)strcopy("PROOF");
|
||||||
|
proof.length = strlen("PROOF");
|
||||||
|
ncerts = 2;
|
||||||
|
certs = malloc(sizeof(spdylay_mem_chunk)*ncerts);
|
||||||
|
certs[0].data = (uint8_t*)strcopy("CERT0");
|
||||||
|
certs[0].length = strlen("CERT0");
|
||||||
|
certs[1].data = (uint8_t*)strcopy("CERT1");
|
||||||
|
certs[1].length = strlen("CERT1");
|
||||||
|
spdylay_frame_credential_init(&frame.credential, SPDYLAY_PROTO_SPDY3,
|
||||||
|
1, &proof, certs, ncerts);
|
||||||
|
framelen = spdylay_frame_pack_credential(&buf, &buflen, &frame.credential);
|
||||||
|
CU_ASSERT(0 == spdylay_frame_unpack_credential
|
||||||
|
(&oframe.credential,
|
||||||
|
&buf[0], SPDYLAY_FRAME_HEAD_LENGTH,
|
||||||
|
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
|
||||||
|
framelen-SPDYLAY_FRAME_HEAD_LENGTH));
|
||||||
|
CU_ASSERT(1 == oframe.credential.slot);
|
||||||
|
CU_ASSERT(5 == oframe.credential.proof.length);
|
||||||
|
CU_ASSERT(memcmp("PROOF", oframe.credential.proof.data, 5) == 0);
|
||||||
|
CU_ASSERT(2 == oframe.credential.ncerts);
|
||||||
|
CU_ASSERT(5 == oframe.credential.certs[0].length);
|
||||||
|
CU_ASSERT(memcmp("CERT0", oframe.credential.certs[0].data, 5) == 0);
|
||||||
|
CU_ASSERT(5 == oframe.credential.certs[1].length);
|
||||||
|
CU_ASSERT(memcmp("CERT1", oframe.credential.certs[1].data, 5) == 0);
|
||||||
|
CU_ASSERT(SPDYLAY_PROTO_SPDY3 == oframe.credential.hd.version);
|
||||||
|
CU_ASSERT(SPDYLAY_CREDENTIAL == oframe.credential.hd.type);
|
||||||
|
CU_ASSERT(SPDYLAY_CTRL_FLAG_NONE == oframe.credential.hd.flags);
|
||||||
|
CU_ASSERT(framelen-SPDYLAY_FRAME_HEAD_LENGTH == oframe.credential.hd.length);
|
||||||
|
spdylay_frame_credential_free(&oframe.credential);
|
||||||
|
|
||||||
|
/* Put large certificate length */
|
||||||
|
spdylay_put_uint32be(&buf[8+2+4+5], INT32_MAX);
|
||||||
|
CU_ASSERT(SPDYLAY_ERR_INVALID_FRAME == spdylay_frame_unpack_credential
|
||||||
|
(&oframe.credential,
|
||||||
|
&buf[0], SPDYLAY_FRAME_HEAD_LENGTH,
|
||||||
|
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
|
||||||
|
framelen-SPDYLAY_FRAME_HEAD_LENGTH));
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
spdylay_frame_credential_free(&frame.credential);
|
||||||
|
}
|
||||||
|
|
||||||
void test_spdylay_frame_nv_sort(void)
|
void test_spdylay_frame_nv_sort(void)
|
||||||
{
|
{
|
||||||
char *nv[7];
|
char *nv[7];
|
||||||
|
@ -670,3 +730,49 @@ void test_spdylay_frame_unpack_nv_check_name_spdy3(void)
|
||||||
test_spdylay_frame_unpack_nv_check_name_with
|
test_spdylay_frame_unpack_nv_check_name_with
|
||||||
(spdylay_frame_get_len_size(SPDYLAY_PROTO_SPDY3));
|
(spdylay_frame_get_len_size(SPDYLAY_PROTO_SPDY3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_spdylay_frame_nv_set_origin(void)
|
||||||
|
{
|
||||||
|
spdylay_origin origin;
|
||||||
|
const char *nv1[] = {
|
||||||
|
":host", "example.org",
|
||||||
|
":scheme", "https",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
const char *nv2[] = {
|
||||||
|
":host", "example.org:8443",
|
||||||
|
":scheme", "https",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
const char *nv3[] = {
|
||||||
|
":host", "example.org:0",
|
||||||
|
":scheme", "https",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
const char *nv4[] = {
|
||||||
|
":host", "example.org",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
const char *nv5[] = {
|
||||||
|
":scheme", "https",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
CU_ASSERT(0 == spdylay_frame_nv_set_origin((char**)nv1, &origin));
|
||||||
|
CU_ASSERT(strcmp("https", origin.scheme) == 0);
|
||||||
|
CU_ASSERT(strcmp("example.org", origin.host) == 0);
|
||||||
|
CU_ASSERT(443 == origin.port);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == spdylay_frame_nv_set_origin((char**)nv2, &origin));
|
||||||
|
CU_ASSERT(strcmp("https", origin.scheme) == 0);
|
||||||
|
CU_ASSERT(strcmp("example.org", origin.host) == 0);
|
||||||
|
CU_ASSERT(8443 == origin.port);
|
||||||
|
|
||||||
|
CU_ASSERT(SPDYLAY_ERR_INVALID_ARGUMENT ==
|
||||||
|
spdylay_frame_nv_set_origin((char**)nv3, &origin));
|
||||||
|
|
||||||
|
CU_ASSERT(SPDYLAY_ERR_INVALID_ARGUMENT ==
|
||||||
|
spdylay_frame_nv_set_origin((char**)nv4, &origin));
|
||||||
|
|
||||||
|
CU_ASSERT(SPDYLAY_ERR_INVALID_ARGUMENT ==
|
||||||
|
spdylay_frame_nv_set_origin((char**)nv5, &origin));
|
||||||
|
}
|
||||||
|
|
|
@ -42,11 +42,13 @@ void test_spdylay_frame_pack_headers_spdy3(void);
|
||||||
void test_spdylay_frame_pack_window_update(void);
|
void test_spdylay_frame_pack_window_update(void);
|
||||||
void test_spdylay_frame_pack_settings_spdy2(void);
|
void test_spdylay_frame_pack_settings_spdy2(void);
|
||||||
void test_spdylay_frame_pack_settings_spdy3(void);
|
void test_spdylay_frame_pack_settings_spdy3(void);
|
||||||
|
void test_spdylay_frame_pack_credential(void);
|
||||||
void test_spdylay_frame_nv_sort(void);
|
void test_spdylay_frame_nv_sort(void);
|
||||||
void test_spdylay_frame_nv_downcase(void);
|
void test_spdylay_frame_nv_downcase(void);
|
||||||
void test_spdylay_frame_nv_2to3(void);
|
void test_spdylay_frame_nv_2to3(void);
|
||||||
void test_spdylay_frame_nv_3to2(void);
|
void test_spdylay_frame_nv_3to2(void);
|
||||||
void test_spdylay_frame_unpack_nv_check_name_spdy2(void);
|
void test_spdylay_frame_unpack_nv_check_name_spdy2(void);
|
||||||
void test_spdylay_frame_unpack_nv_check_name_spdy3(void);
|
void test_spdylay_frame_unpack_nv_check_name_spdy3(void);
|
||||||
|
void test_spdylay_frame_nv_set_origin(void);
|
||||||
|
|
||||||
#endif /* SPDYLAY_FRAME_TEST_H */
|
#endif /* SPDYLAY_FRAME_TEST_H */
|
||||||
|
|
|
@ -1924,7 +1924,7 @@ void test_spdylay_session_on_settings_received(void)
|
||||||
iv[2].value = 64*1024;
|
iv[2].value = 64*1024;
|
||||||
iv[2].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
|
iv[2].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
|
||||||
|
|
||||||
iv[3].settings_id = SPDYLAY_SETTINGS_CURRENT_CWND;
|
iv[3].settings_id = SPDYLAY_SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE;
|
||||||
iv[3].value = 512;
|
iv[3].value = 512;
|
||||||
iv[3].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
|
iv[3].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
|
||||||
|
|
||||||
|
@ -1933,7 +1933,7 @@ void test_spdylay_session_on_settings_received(void)
|
||||||
iv[4].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
|
iv[4].flags = SPDYLAY_ID_FLAG_SETTINGS_NONE;
|
||||||
|
|
||||||
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
|
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
|
||||||
spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY3, &callbacks,
|
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY3, &callbacks,
|
||||||
&user_data);
|
&user_data);
|
||||||
session->remote_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE] = 16*1024;
|
session->remote_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE] = 16*1024;
|
||||||
|
|
||||||
|
@ -1953,8 +1953,11 @@ void test_spdylay_session_on_settings_received(void)
|
||||||
session->remote_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS]);
|
session->remote_settings[SPDYLAY_SETTINGS_MAX_CONCURRENT_STREAMS]);
|
||||||
CU_ASSERT(64*1024 ==
|
CU_ASSERT(64*1024 ==
|
||||||
session->remote_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE]);
|
session->remote_settings[SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE]);
|
||||||
CU_ASSERT(512 ==
|
/* We limit certificate vector in reasonable size. */
|
||||||
session->remote_settings[SPDYLAY_SETTINGS_CURRENT_CWND]);
|
CU_ASSERT(SPDYLAY_MAX_CLIENT_CERT_VECTOR_LENGTH ==
|
||||||
|
session->remote_settings
|
||||||
|
[SPDYLAY_SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE]);
|
||||||
|
CU_ASSERT(SPDYLAY_MAX_CLIENT_CERT_VECTOR_LENGTH == session->cli_certvec.size);
|
||||||
CU_ASSERT(64*1024 == stream1->window_size);
|
CU_ASSERT(64*1024 == stream1->window_size);
|
||||||
CU_ASSERT(0 == stream2->window_size);
|
CU_ASSERT(0 == stream2->window_size);
|
||||||
|
|
||||||
|
@ -2064,3 +2067,157 @@ void test_spdylay_session_get_outbound_queue_size(void)
|
||||||
|
|
||||||
spdylay_session_del(session);
|
spdylay_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t get_credential_ncerts(spdylay_session *session,
|
||||||
|
const spdylay_origin *origin,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
if(strcmp("example.org", origin->host) == 0 &&
|
||||||
|
strcmp("https", origin->scheme) == 0 &&
|
||||||
|
443 == origin->port) {
|
||||||
|
return 2;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t get_credential_cert(spdylay_session *session,
|
||||||
|
const spdylay_origin *origin,
|
||||||
|
size_t index,
|
||||||
|
uint8_t *cert, size_t certlen,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
size_t len = strlen(origin->host);
|
||||||
|
if(certlen == 0) {
|
||||||
|
return len;
|
||||||
|
} else {
|
||||||
|
assert(certlen == len);
|
||||||
|
memcpy(cert, origin->host, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t get_credential_proof(spdylay_session *session,
|
||||||
|
const spdylay_origin *origin,
|
||||||
|
uint8_t *proof, size_t prooflen,
|
||||||
|
void *uer_data)
|
||||||
|
{
|
||||||
|
size_t len = strlen(origin->scheme);
|
||||||
|
if(prooflen == 0) {
|
||||||
|
return len;
|
||||||
|
} else {
|
||||||
|
assert(prooflen == len);
|
||||||
|
memcpy(proof, origin->scheme, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_spdylay_session_prep_credential(void)
|
||||||
|
{
|
||||||
|
spdylay_session *session;
|
||||||
|
spdylay_session_callbacks callbacks;
|
||||||
|
const char *nv[] = { ":host", "example.org",
|
||||||
|
":scheme", "https",
|
||||||
|
NULL };
|
||||||
|
const char *nv_nocert[] = { ":host", "nocert",
|
||||||
|
":scheme", "https",
|
||||||
|
NULL };
|
||||||
|
spdylay_frame frame, *cred_frame;
|
||||||
|
spdylay_outbound_item *item;
|
||||||
|
size_t i;
|
||||||
|
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
|
||||||
|
callbacks.get_credential_ncerts = get_credential_ncerts;
|
||||||
|
callbacks.get_credential_cert = get_credential_cert;
|
||||||
|
callbacks.get_credential_proof = get_credential_proof;
|
||||||
|
CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY3,
|
||||||
|
&callbacks, NULL));
|
||||||
|
spdylay_frame_syn_stream_init(&frame.syn_stream, session->version,
|
||||||
|
SPDYLAY_CTRL_FLAG_NONE, 1, 0, 0,
|
||||||
|
dup_nv(nv));
|
||||||
|
CU_ASSERT(SPDYLAY_ERR_CREDENTIAL_PENDING ==
|
||||||
|
spdylay_session_prep_credential(session, &frame.syn_stream));
|
||||||
|
item = spdylay_session_get_next_ob_item(session);
|
||||||
|
CU_ASSERT(SPDYLAY_CREDENTIAL == OB_CTRL_TYPE(item));
|
||||||
|
CU_ASSERT(SPDYLAY_OB_PRI_CREDENTIAL == item->pri);
|
||||||
|
cred_frame = OB_CTRL(item);
|
||||||
|
CU_ASSERT(strlen("https") == cred_frame->credential.proof.length);
|
||||||
|
CU_ASSERT(memcmp("https", cred_frame->credential.proof.data,
|
||||||
|
cred_frame->credential.proof.length) == 0);
|
||||||
|
CU_ASSERT(2 == cred_frame->credential.ncerts);
|
||||||
|
for(i = 0; i < cred_frame->credential.ncerts; ++i) {
|
||||||
|
CU_ASSERT(strlen("example.org") == cred_frame->credential.certs[i].length);
|
||||||
|
CU_ASSERT(memcmp("example.org", cred_frame->credential.certs[i].data,
|
||||||
|
cred_frame->credential.certs[i].length) == 0);
|
||||||
|
}
|
||||||
|
/* Next spdylay_session_get_next_ob_item() call returns slot index */
|
||||||
|
CU_ASSERT(1 == spdylay_session_prep_credential(session, &frame.syn_stream));
|
||||||
|
|
||||||
|
spdylay_frame_syn_stream_free(&frame.syn_stream);
|
||||||
|
|
||||||
|
spdylay_frame_syn_stream_init(&frame.syn_stream, session->version,
|
||||||
|
SPDYLAY_CTRL_FLAG_NONE, 1, 0, 0,
|
||||||
|
dup_nv(nv_nocert));
|
||||||
|
CU_ASSERT(0 == spdylay_session_prep_credential(session, &frame.syn_stream));
|
||||||
|
spdylay_frame_syn_stream_free(&frame.syn_stream);
|
||||||
|
|
||||||
|
spdylay_session_del(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_spdylay_submit_syn_stream_with_credential(void)
|
||||||
|
{
|
||||||
|
spdylay_session *session;
|
||||||
|
spdylay_session_callbacks callbacks;
|
||||||
|
const char *nv[] = { ":host", "example.org",
|
||||||
|
":scheme", "https",
|
||||||
|
NULL };
|
||||||
|
my_user_data ud;
|
||||||
|
accumulator acc;
|
||||||
|
|
||||||
|
ud.acc = &acc;
|
||||||
|
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
|
||||||
|
callbacks.send_callback = block_count_send_callback;
|
||||||
|
callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
|
||||||
|
callbacks.get_credential_ncerts = get_credential_ncerts;
|
||||||
|
callbacks.get_credential_cert = get_credential_cert;
|
||||||
|
callbacks.get_credential_proof = get_credential_proof;
|
||||||
|
|
||||||
|
CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY3,
|
||||||
|
&callbacks, &ud));
|
||||||
|
|
||||||
|
CU_ASSERT(0 == spdylay_submit_request(session, 0, nv, NULL, NULL));
|
||||||
|
|
||||||
|
ud.block_count = 1;
|
||||||
|
ud.ctrl_send_cb_called = 0;
|
||||||
|
CU_ASSERT(0 == spdylay_session_send(session));
|
||||||
|
|
||||||
|
CU_ASSERT(1 == ud.ctrl_send_cb_called);
|
||||||
|
CU_ASSERT(SPDYLAY_CREDENTIAL == ud.sent_frame_type);
|
||||||
|
|
||||||
|
session->callbacks.send_callback = accumulator_send_callback;
|
||||||
|
acc.length = 0;
|
||||||
|
ud.ctrl_send_cb_called = 0;
|
||||||
|
CU_ASSERT(0 == spdylay_session_send(session));
|
||||||
|
CU_ASSERT(1 == ud.ctrl_send_cb_called);
|
||||||
|
CU_ASSERT(SPDYLAY_SYN_STREAM == ud.sent_frame_type);
|
||||||
|
/* Check slot */
|
||||||
|
CU_ASSERT(1 == acc.buf[17]);
|
||||||
|
|
||||||
|
spdylay_session_del(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_spdylay_session_set_initial_client_cert_origin(void)
|
||||||
|
{
|
||||||
|
spdylay_session *session;
|
||||||
|
spdylay_session_callbacks callbacks;
|
||||||
|
const spdylay_origin *origin;
|
||||||
|
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY3, &callbacks, NULL);
|
||||||
|
CU_ASSERT(0 == spdylay_session_set_initial_client_cert_origin
|
||||||
|
(session, "https", "example.org", 443));
|
||||||
|
origin = spdylay_session_get_client_cert_origin(session, 1);
|
||||||
|
CU_ASSERT(NULL != origin);
|
||||||
|
CU_ASSERT(strcmp("https", spdylay_origin_get_scheme(origin)) == 0);
|
||||||
|
CU_ASSERT(strcmp("example.org", spdylay_origin_get_host(origin)) == 0);
|
||||||
|
CU_ASSERT(443 == spdylay_origin_get_port(origin));
|
||||||
|
|
||||||
|
spdylay_session_del(session);
|
||||||
|
}
|
||||||
|
|
|
@ -64,5 +64,8 @@ void test_spdylay_session_on_ctrl_not_send(void);
|
||||||
void test_spdylay_session_on_settings_received(void);
|
void test_spdylay_session_on_settings_received(void);
|
||||||
void test_spdylay_submit_settings(void);
|
void test_spdylay_submit_settings(void);
|
||||||
void test_spdylay_session_get_outbound_queue_size(void);
|
void test_spdylay_session_get_outbound_queue_size(void);
|
||||||
|
void test_spdylay_session_prep_credential(void);
|
||||||
|
void test_spdylay_submit_syn_stream_with_credential(void);
|
||||||
|
void test_spdylay_session_set_initial_client_cert_origin(void);
|
||||||
|
|
||||||
#endif /* SPDYLAY_SESSION_TEST_H */
|
#endif /* SPDYLAY_SESSION_TEST_H */
|
||||||
|
|
Loading…
Reference in New Issue