ssl: Add support for the new 16.0.0 functionality.

This commit is contained in:
yellows8 2023-03-09 23:14:40 -05:00
parent 8d9959010f
commit f64d2059c4
No known key found for this signature in database
GPG Key ID: 0AF90DA3F1E60E43
4 changed files with 316 additions and 7 deletions

View File

@ -46,6 +46,9 @@ int socketSslConnectionSetSocketDescriptor(SslConnection *c, int sockfd);
/// Wrapper for \ref sslConnectionGetSocketDescriptor. Returns the output sockfd on success and -1 on error.
int socketSslConnectionGetSocketDescriptor(SslConnection *c);
/// Wrapper for \ref sslConnectionSetDtlsSocketDescriptor. Returns the output sockfd on success and -1 on error. errno==ENOENT indicates that no sockfd was returned, this error must be ignored.
int socketSslConnectionSetDtlsSocketDescriptor(SslConnection *c, int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/// Wrapper for \ref nifmRequestRegisterSocketDescriptor. Returns 0 on success and -1 on error.
int socketNifmRequestRegisterSocketDescriptor(NifmRequest* r, int sockfd);

View File

@ -177,6 +177,11 @@ typedef enum {
SslOptionType_EnableAlpn = 3, ///< [9.0.0+] EnableAlpn. Only available with \ref sslConnectionSetOption. \ref sslConnectionSetSocketDescriptor should have been used prior to this - this will optionally use state setup by that, without throwing an error if that cmd wasn't used.
} SslOptionType;
/// PrivateOptionType
typedef enum {
SslPrivateOptionType_DtlsSession = 1, ///< \ref sslConnectionSetSessionCacheMode will throw an error if the input ::SslSessionCacheMode is non-zero and this option flag is set.
} SslPrivateOptionType;
/// AlpnProtoState
typedef enum {
SslAlpnProtoState_NoSupport = 0, ///< NoSupport
@ -223,6 +228,15 @@ typedef struct {
char protocol_version[0x8]; ///< Protocol version string.
} SslCipherInfo;
/// KeyAndCertParams
typedef struct {
u32 unk_x0; ///< Must be value 1.
s32 key_size; ///< Key size in bits.
u64 public_exponent; ///< Public exponent, must be non-zero. Only the low 4-bytes are used.
char common_name[0x40]; ///< CN (Common Name) NUL-terminated string.
u32 common_name_len; ///< Length of common_name excluding NUL-terminator. Must be 0x1-0x3F.
} SslKeyAndCertParams;
/// Initialize ssl. A default value of 0x3 can be used for num_sessions. This must be 0x1-0x4.
Result sslInitialize(u32 num_sessions);
@ -413,6 +427,34 @@ Result sslContextAddPolicyOid(SslContext *c, const char *str, u32 str_bufsize);
*/
Result sslContextImportCrl(SslContext *c, const void* buffer, u32 size, u64 *id);
/**
* @brief ImportClientCertKeyPki
* @note Only available on [16.0.0+].
* @param c \ref SslContext
* @param[in] cert Input cert buffer,
* @param[in] cert_size Size of the cert buffer.
* @param[in] key Input key buffer.
* @param[in] key_size Size of the key buffer.
* @param[in] format \ref SslCertificateFormat for the cert and key.
* @param[out] id Output Id. Optional, can be NULL.
*/
Result sslContextImportClientCertKeyPki(SslContext *c, const void* cert, u32 cert_size, const void* key, u32 key_size, SslCertificateFormat format, u64 *id);
/**
* @brief GeneratePrivateKeyAndCert
* @note Only available on [16.0.0+].
* @param c \ref SslContext
* @param[out] cert Output cert buffer,
* @param[in] cert_size Size of the cert buffer.
* @param[out] key Output key buffer.
* @param[in] key_size Size of the key buffer.
* @param[in] val Must be value 1.
* @param[in] params \ref SslKeyAndCertParams
* @param[out] out_certsize Actual size of the generated cert data.
* @param[out] out_keysize Actual size of the generated key data.
*/
Result sslContextGeneratePrivateKeyAndCert(SslContext *c, void* cert, u32 cert_size, void* key, u32 key_size, u32 val, const SslKeyAndCertParams *params, u32 *out_certsize, u32 *out_keysize);
/**
* @brief CreateConnectionForSystem
* @note Only available on [15.0.0+] with ::SslServiceType_System.
@ -680,5 +722,80 @@ Result sslConnectionSetNextAlpnProto(SslConnection *c, const u8 *buffer, u32 siz
*/
Result sslConnectionGetNextAlpnProto(SslConnection *c, SslAlpnProtoState *state, u32 *out, u8 *buffer, u32 size);
/**
* @brief SetDtlsSocketDescriptor. Do not use directly, use \ref socketSslConnectionSetDtlsSocketDescriptor instead.
* @note Only available on [16.0.0+].
* @note An error is thrown if this was used previously.
* @param c \ref SslConnection
* @param[in] sockfd sockfd
* @param[in] Input sockaddr.
* @param[in] size Input sockaddr size.
* @param[out] out_sockfd sockfd. Prior to using \ref sslConnectionClose, this must be closed if it's not negative (it will be -1 if ::SslOptionType_DoNotCloseSocket is set).
*/
Result sslConnectionSetDtlsSocketDescriptor(SslConnection *c, int sockfd, const void* buf, size_t size, int *out_sockfd);
/**
* @brief GetDtlsHandshakeTimeout
* @note Only available on [16.0.0+].
* @param c \ref SslConnection
* @param[out] out Output nanoseconds value.
*/
Result sslConnectionGetDtlsHandshakeTimeout(SslConnection *c, u64 *out);
/**
* @brief SetPrivateOption
* @note Only available on [16.0.0+].
* @param c \ref SslConnection
* @param[in] option \ref SslPrivateOptionType
* @param[in] flag Input flag value.
*/
Result sslConnectionSetPrivateOption(SslConnection *c, SslPrivateOptionType option, bool flag);
/**
* @brief SetSrtpCiphers
* @note Only available on [16.0.0+].
* @param c \ref SslConnection
* @param[in] ciphers Input array of u16s. Each entry must be value 1-2, otherwise the entry is ignored.
* @param[in] count Total entries in the ciphers array, the maximum is 4.
*/
Result sslConnectionSetSrtpCiphers(SslConnection *c, const u16 *ciphers, u32 count);
/**
* @brief GetSrtpCipher
* @note Only available on [16.0.0+].
* @param c \ref SslConnection
* @param[out] out Output value.
*/
Result sslConnectionGetSrtpCipher(SslConnection *c, u16 *out);
/**
* @brief ExportKeyingMaterial
* @note Only available on [16.0.0+].
* @param c \ref SslConnection
* @param[out] outbuf Output buffer.
* @param[in] outbuf_size Output buffer size.
* @param[in] label Input label string.
* @param[in] label_size Size of the label buffer excluding NUL-terminator.
* @param[in] context Optional input context buffer, can be NULL.
* @param[in] context_size Size of context, if specified this must be <0xFFFF.
*/
Result sslConnectionExportKeyingMaterial(SslConnection *c, u8 *outbuf, u32 outbuf_size, const char *label, u32 label_size, const void* context, u32 context_size);
/**
* @brief SetIoTimeout
* @note Only available on [16.0.0+].
* @param c \ref SslConnection
* @param[in] timeout Input timeout value.
*/
Result sslConnectionSetIoTimeout(SslConnection *c, u32 timeout);
/**
* @brief GetIoTimeout
* @note Only available on [16.0.0+].
* @param c \ref SslConnection
* @param[out] out Output timeout value.
*/
Result sslConnectionGetIoTimeout(SslConnection *c, u32 *out);
///@}

View File

@ -199,6 +199,39 @@ int socketSslConnectionGetSocketDescriptor(SslConnection *c) {
return fd;
}
int socketSslConnectionSetDtlsSocketDescriptor(SslConnection *c, int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
int dev;
int fd = _socketGetFd(sockfd);
if (fd==-1)
return -1;
int tmpfd=0;
Result rc = sslConnectionSetDtlsSocketDescriptor(c, fd, addr, addrlen, &tmpfd);
if (R_FAILED(rc)) {
g_bsdResult = rc;
errno = EIO;
return -1;
}
if (tmpfd==-1) { // The cmd didn't return a sockfd. This error must be ignored.
errno = ENOENT;
return -1;
}
dev = FindDevice("soc:");
if(dev == -1)
return -1;
fd = __alloc_handle(dev);
if(fd == -1)
return -1;
*(int *)__get_handle(fd)->fileStruct = tmpfd;
return fd;
}
int socketNifmRequestRegisterSocketDescriptor(NifmRequest* r, int sockfd) {
int fd = _socketGetFd(sockfd);

View File

@ -125,6 +125,16 @@ static Result _sslCmdInU64NoOut(Service* srv, u64 inval, u32 cmd_id) {
return _sslObjectDispatchIn(srv, cmd_id, inval);
}
static Result _sslCmdInU8U32NoOut(Service* srv, u8 val0, u32 val1, u32 cmd_id) {
const struct {
u8 val0;
u8 pad[3];
u32 val1;
} in = { val0, {0}, val1 };
return _sslObjectDispatchIn(srv, cmd_id, in);
}
static Result _sslCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
return _sslObjectDispatchOut(srv, cmd_id, *out);
}
@ -502,6 +512,57 @@ Result sslContextImportCrl(SslContext *c, const void* buffer, u32 size, u64 *id)
);
}
Result sslContextImportClientCertKeyPki(SslContext *c, const void* cert, u32 cert_size, const void* key, u32 key_size, SslCertificateFormat format, u64 *id) {
if (!serviceIsActive(&c->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(16,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
u32 tmp=format;
return _sslObjectDispatchInOut(&c->s, 12, tmp, *id,
.buffer_attrs = {
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
},
.buffers = {
{ cert, cert_size },
{ key, key_size },
},
);
}
Result sslContextGeneratePrivateKeyAndCert(SslContext *c, void* cert, u32 cert_size, void* key, u32 key_size, u32 val, const SslKeyAndCertParams *params, u32 *out_certsize, u32 *out_keysize) {
if (!serviceIsActive(&c->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(16,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
struct {
u32 out_certsize;
u32 out_keysize;
} out;
Result rc = _sslObjectDispatchInOut(&c->s, 13, val, out,
.buffer_attrs = {
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
},
.buffers = {
{ cert, cert_size },
{ key, key_size },
{ params, sizeof(*params) },
},
);
if (R_SUCCEEDED(rc)) {
if (out_certsize) *out_certsize = out.out_certsize;
if (out_keysize) *out_keysize = out.out_keysize;
}
return rc;
}
Result sslContextCreateConnectionForSystem(SslContext *c, SslConnection *conn) {
if (hosversionBefore(15,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
@ -729,13 +790,7 @@ Result sslConnectionSetOption(SslConnection *c, SslOptionType option, bool flag)
if (!serviceIsActive(&c->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
const struct {
u8 flag;
u8 pad[3];
u32 option;
} in = { flag!=0, {0}, option };
return _sslObjectDispatchIn(&c->s, 22, in);
return _sslCmdInU8U32NoOut(&c->s, flag!=0, option, 22);
}
Result sslConnectionGetOption(SslConnection *c, SslOptionType option, bool *out) {
@ -812,3 +867,104 @@ Result sslConnectionGetNextAlpnProto(SslConnection *c, SslAlpnProtoState *state,
return rc;
}
Result sslConnectionSetDtlsSocketDescriptor(SslConnection *c, int sockfd, const void* buf, size_t size, int *out_sockfd) {
if (!serviceIsActive(&c->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(16,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _sslObjectDispatchInOut(&c->s, 28, sockfd, *out_sockfd,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
.buffers = {
{ buf, size },
},
);
}
Result sslConnectionGetDtlsHandshakeTimeout(SslConnection *c, u64 *out) {
if (!serviceIsActive(&c->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(16,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _sslObjectDispatch(&c->s, 29,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = {
{ out, sizeof(*out) },
},
);
}
Result sslConnectionSetPrivateOption(SslConnection *c, SslPrivateOptionType option, bool flag) {
if (!serviceIsActive(&c->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(16,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _sslCmdInU8U32NoOut(&c->s, flag!=0, option, 30);
}
Result sslConnectionSetSrtpCiphers(SslConnection *c, const u16 *ciphers, u32 count) {
if (!serviceIsActive(&c->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(16,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _sslCmdInBufNoOut(&c->s, ciphers, count*sizeof(u16), 31);
}
Result sslConnectionGetSrtpCipher(SslConnection *c, u16 *out) {
if (!serviceIsActive(&c->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(16,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _sslObjectDispatchOut(&c->s, 32, *out);
}
Result sslConnectionExportKeyingMaterial(SslConnection *c, u8 *outbuf, u32 outbuf_size, const char *label, u32 label_size, const void* context, u32 context_size) {
if (!serviceIsActive(&c->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(16,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _sslObjectDispatch(&c->s, 33,
.buffer_attrs = {
SfBufferAttr_HipcMapAlias | SfBufferAttr_Out,
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
},
.buffers = {
{ outbuf, outbuf_size },
{ label, label_size },
{ context, context_size },
},
);
}
Result sslConnectionSetIoTimeout(SslConnection *c, u32 timeout) {
if (!serviceIsActive(&c->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(16,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _sslCmdInU32NoOut(&c->s, timeout, 34);
}
Result sslConnectionGetIoTimeout(SslConnection *c, u32 *out) {
if (!serviceIsActive(&c->s))
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(16,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _sslCmdNoInOutU32(&c->s, out, 35);
}