diff --git a/nx/include/switch/services/ssl.h b/nx/include/switch/services/ssl.h index a6594e4c..9e8c9996 100644 --- a/nx/include/switch/services/ssl.h +++ b/nx/include/switch/services/ssl.h @@ -10,7 +10,7 @@ /// CaCertificateId typedef enum { - SslCaCertificateId_All = -1, ///< All + SslCaCertificateId_All = -1, ///< [3.0.0+] All SslCaCertificateId_NintendoCAG3 = 1, ///< NintendoCAG3 SslCaCertificateId_NintendoClass2CAG3 = 2, ///< NintendoClass2CAG3 @@ -32,10 +32,10 @@ typedef enum { SslCaCertificateId_EntrustnetCertificationAuthority2048 = 1014, ///< EntrustnetCertificationAuthority2048 SslCaCertificateId_EntrustRootCertificationAuthority = 1015, ///< EntrustRootCertificationAuthority SslCaCertificateId_EntrustRootCertificationAuthorityG2 = 1016, ///< EntrustRootCertificationAuthorityG2 - SslCaCertificateId_GeoTrustGlobalCA2 = 1017, ///< GeoTrustGlobalCA2 - SslCaCertificateId_GeoTrustGlobalCA = 1018, ///< GeoTrustGlobalCA - SslCaCertificateId_GeoTrustPrimaryCertificationAuthorityG3 = 1019, ///< GeoTrustPrimaryCertificationAuthorityG3 - SslCaCertificateId_GeoTrustPrimaryCertificationAuthority = 1020, ///< GeoTrustPrimaryCertificationAuthority + SslCaCertificateId_GeoTrustGlobalCA2 = 1017, ///< GeoTrustGlobalCA2 ([8.0.0+] ::SslTrustedCertStatus is ::SslTrustedCertStatus_EnabledNotTrusted) + SslCaCertificateId_GeoTrustGlobalCA = 1018, ///< GeoTrustGlobalCA ([8.0.0+] ::SslTrustedCertStatus is ::SslTrustedCertStatus_EnabledNotTrusted) + SslCaCertificateId_GeoTrustPrimaryCertificationAuthorityG3 = 1019, ///< GeoTrustPrimaryCertificationAuthorityG3 ([8.0.0+] ::SslTrustedCertStatus is ::SslTrustedCertStatus_EnabledNotTrusted) + SslCaCertificateId_GeoTrustPrimaryCertificationAuthority = 1020, ///< GeoTrustPrimaryCertificationAuthority ([8.0.0+] ::SslTrustedCertStatus is ::SslTrustedCertStatus_EnabledNotTrusted) SslCaCertificateId_GlobalSignRootCA = 1021, ///< GlobalSignRootCA SslCaCertificateId_GlobalSignRootCAR2 = 1022, ///< GlobalSignRootCAR2 SslCaCertificateId_GlobalSignRootCAR3 = 1023, ///< GlobalSignRootCAR3 @@ -43,12 +43,12 @@ typedef enum { SslCaCertificateId_GoDaddyRootCertificateAuthorityG2 = 1025, ///< GoDaddyRootCertificateAuthorityG2 SslCaCertificateId_StarfieldClass2CertificationAuthority = 1026, ///< StarfieldClass2CertificationAuthority SslCaCertificateId_StarfieldRootCertificateAuthorityG2 = 1027, ///< StarfieldRootCertificateAuthorityG2 - SslCaCertificateId_thawtePrimaryRootCAG3 = 1028, ///< thawtePrimaryRootCAG3 - SslCaCertificateId_thawtePrimaryRootCA = 1029, ///< thawtePrimaryRootCA - SslCaCertificateId_VeriSignClass3PublicPrimaryCertificationAuthorityG3 = 1030, ///< VeriSignClass3PublicPrimaryCertificationAuthorityG3 - SslCaCertificateId_VeriSignClass3PublicPrimaryCertificationAuthorityG5 = 1031, ///< VeriSignClass3PublicPrimaryCertificationAuthorityG5 - SslCaCertificateId_VeriSignUniversalRootCertificationAuthority = 1032, ///< VeriSignUniversalRootCertificationAuthority - SslCaCertificateId_DSTRootCAX3 = 1033, ///< DSTRootCAX3 + SslCaCertificateId_thawtePrimaryRootCAG3 = 1028, ///< thawtePrimaryRootCAG3 ([8.0.0+] ::SslTrustedCertStatus is ::SslTrustedCertStatus_EnabledNotTrusted) + SslCaCertificateId_thawtePrimaryRootCA = 1029, ///< thawtePrimaryRootCA ([8.0.0+] ::SslTrustedCertStatus is ::SslTrustedCertStatus_EnabledNotTrusted) + SslCaCertificateId_VeriSignClass3PublicPrimaryCertificationAuthorityG3 = 1030, ///< VeriSignClass3PublicPrimaryCertificationAuthorityG3 ([8.0.0+] ::SslTrustedCertStatus is ::SslTrustedCertStatus_EnabledNotTrusted) + SslCaCertificateId_VeriSignClass3PublicPrimaryCertificationAuthorityG5 = 1031, ///< VeriSignClass3PublicPrimaryCertificationAuthorityG5 ([8.0.0+] ::SslTrustedCertStatus is ::SslTrustedCertStatus_EnabledNotTrusted) + SslCaCertificateId_VeriSignUniversalRootCertificationAuthority = 1032, ///< VeriSignUniversalRootCertificationAuthority ([8.0.0+] ::SslTrustedCertStatus is ::SslTrustedCertStatus_EnabledNotTrusted) + SslCaCertificateId_DSTRootCAX3 = 1033, ///< [6.0.0+] DSTRootCAX3 } SslCaCertificateId; /// TrustedCertStatus @@ -92,10 +92,12 @@ typedef enum { /// ContextOption typedef enum { - SslContextOption_CrlImportDateCheckEnable = 1, ///< CrlImportDateCheckEnable + SslContextOption_CrlImportDateCheckEnable = 1, ///< CrlImportDateCheckEnable. The default value at the time of \ref sslCreateContext is value 1. } SslContextOption; -/// VerifyOption +/// VerifyOption. The default bitmask value at the time of \ref sslContextCreateConnection is ::SslVerifyOption_PeerCa | ::SslVerifyOption_HostName. +/// [5.0.0+] \ref sslConnectionSetVerifyOption: (::SslVerifyOption_PeerCa | ::SslVerifyOption_HostName) must be set, unless: ::SslOptionType_SkipDefaultVerify is set, or [9.0.0+] ::SslDebugOptionType_AllowDisableVerifyOption is set. +/// [6.0.0+] \ref sslConnectionSetVerifyOption: Following that, if ::SslVerifyOption_EvPolicyOid is set, then the following options must be set (besides the previously mentioned one): ::SslVerifyOption_PeerCa and ::SslVerifyOption_DateCheck. typedef enum { SslVerifyOption_PeerCa = BIT(0), ///< PeerCa SslVerifyOption_HostName = BIT(1), ///< HostName @@ -105,7 +107,7 @@ typedef enum { SslVerifyOption_EvCertFingerprint = BIT(5), ///< [6.0.0+] EvCertFingerprint } SslVerifyOption; -/// IoMode +/// IoMode. The default value at the time of \ref sslContextCreateConnection is ::SslIoMode_Blocking. typedef enum { SslIoMode_Blocking = 1, ///< Blocking SslIoMode_NonBlocking = 2, ///< NonBlocking @@ -131,12 +133,12 @@ typedef enum { SslRenegotiationMode_Secure = 1, ///< Secure } SslRenegotiationMode; -/// OptionType +/// OptionType. The default bool flags value for these at the time of \ref sslContextCreateConnection is cleared. typedef enum { - SslOptionType_DoNotCloseSocket = 0, ///< DoNotCloseSocket + SslOptionType_DoNotCloseSocket = 0, ///< DoNotCloseSocket. See \ref sslConnectionClose. This is only available if \ref sslConnectionSetSocketDescriptor wasn't used yet. SslOptionType_GetServerCertChain = 1, ///< [3.0.0+] GetServerCertChain - SslOptionType_SkipDefaultVerify = 2, ///< [5.0.0+] SkipDefaultVerify - SslOptionType_EnableAlpn = 3, ///< [9.0.0+] EnableAlpn + SslOptionType_SkipDefaultVerify = 2, ///< [5.0.0+] SkipDefaultVerify. Checked by \ref sslConnectionSetVerifyOption, see \ref SslVerifyOption. + 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; /// AlpnProtoState @@ -161,12 +163,18 @@ typedef struct { /// BuiltInCertificateInfo typedef struct { - u32 cert_id; ///< CaCertificateId + u32 cert_id; ///< \ref SslCaCertificateId u32 status; ///< \ref SslTrustedCertStatus u64 cert_size; ///< CertificateSize u8 *cert_data; ///< CertificateData (converted from an offset to a ptr), in DER format. } SslBuiltInCertificateInfo; +/// CipherInfo +typedef struct { + char cipher[0x40]; ///< Cipher string. + char protocol_version[0x8]; ///< Protocol version string. +} SslCipherInfo; + /// Initialize ssl. A default value of 0x3 can be used for num_sessions. This must be 0x1-0x4. Result sslInitialize(u32 num_sessions); @@ -196,8 +204,9 @@ Result sslGetContextCount(u32 *out); * @param[in] size Output buffer size, this should be the size from \ref sslGetCertificateBufSize. * @param[in] ca_cert_ids Input array of \ref SslCaCertificateId. * @param[in] count Size of the ca_cert_ids array in entries. + * @param[out] total_out [3.0.0+] Total output entries. Will always match count on pre-3.0.0. This will differ from count when ::SslCaCertificateId_All is used. */ -Result sslGetCertificates(void* buffer, u32 size, u32 *ca_cert_ids, u32 count); +Result sslGetCertificates(void* buffer, u32 size, u32 *ca_cert_ids, u32 count, u32 *total_out); /** * @brief GetCertificateBufSize @@ -272,7 +281,7 @@ Result sslContextCreateConnection(SslContext *c, SslConnection *conn); /** * @brief GetConnectionCount - * @note Not used by official sw. + * @note Not exposed by official sw. * @param c \ref SslContext * @param[out] out Output value. */ @@ -318,7 +327,7 @@ Result sslContextRegisterInternalPki(SslContext *c, SslInternalPki internal_pki, * @brief AddPolicyOid * @param c \ref SslContext * @param[in] str Input string. - * @param[in] str_bufsize String buffer size, excluding NUL-terminator. Hence, this should be actual_bufsize-1. This must not be >0xff. + * @param[in] str_bufsize String buffer size, excluding NUL-terminator (must not match the string length). Hence, this should be actual_bufsize-1. This must not be >0xff. */ Result sslContextAddPolicyOid(SslContext *c, const char* str, u32 str_bufsize); @@ -339,13 +348,14 @@ Result sslContextImportCrl(SslContext *c, const void* buffer, u32 size, u64 *id) /** * @brief Closes a Connection object. - * @note This will use close() with the sockfd previously set by \ref sslConnectionSetSocketDescriptor if needed, hence sockets must have been initialized prior to using this. + * @note This will use close() with the sockfd previously set by \ref sslConnectionSetSocketDescriptor if needed, hence sockets must have been initialized prior to using this. This can essentially be disabled via ::SslOptionType_DoNotCloseSocket. * @param c \ref SslConnection */ void sslConnectionClose(SslConnection *c); /** * @brief SetSocketDescriptor + * @note An error is thrown if this was used previously. * @param c \ref SslConnection * @param[in] sockfd sockfd */ @@ -368,6 +378,7 @@ Result sslConnectionSetVerifyOption(SslConnection *c, u32 verify_option); /** * @brief SetIoMode + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. * @param c \ref SslConnection * @param[in] mode \ref SslIoMode */ @@ -375,6 +386,7 @@ Result sslConnectionSetIoMode(SslConnection *c, SslIoMode mode); /** * @brief GetSocketDescriptor + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. * @param c \ref SslConnection * @param[out] sockfd Output sockfd. */ @@ -389,19 +401,190 @@ Result sslConnectionGetSocketDescriptor(SslConnection *c, int *sockfd); */ Result sslConnectionGetHostName(SslConnection *c, char* str, u32 str_bufsize, u32 *out); +/** + * @brief GetVerifyOption + * @param c \ref SslConnection + * @param[out] out Output bitmask of \ref SslVerifyOption. + */ +Result sslConnectionGetVerifyOption(SslConnection *c, u32 *out); + +/** + * @brief GetIoMode + * @param c \ref SslConnection + * @param[out] out \ref SslIoMode + */ +Result sslConnectionGetIoMode(SslConnection *c, SslIoMode *out); + +/** + * @brief DoHandshake + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. + * @note \ref sslConnectionSetHostName must have been used previously with a non-empty string when ::SslVerifyOption_HostName is set. + * @note The DoHandshakeGetServerCert cmd is only used if both server_certbuf/server_certbuf_size are set, otherwise the DoHandshake cmd is used (in which case out0/out1 will be left at value 0). + * @param c \ref SslConnection + * @param[out] out0 Optional first output value, can be NULL. + * @param[out] out1 Optional second output value, can be NULL. + * @param[out] server_certbuf Optional output server cert buffer, can be NULL. + * @param[in] server_certbuf_size Optional output server cert buffer size, can be 0. + */ +Result sslConnectionDoHandshake(SslConnection *c, u32 *out0, u32 *out1, void* server_certbuf, u32 server_certbuf_size); + +/** + * @brief Read + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. + * @param c \ref SslConnection + * @param[out] buffer Output buffer, must not be NULL. + * @param[in] size Output buffer size, must not be 0. + * @param[out] out Output value. + */ +Result sslConnectionRead(SslConnection *c, void* buffer, u32 size, u32 *out); + +/** + * @brief Write + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. + * @param c \ref SslConnection + * @param[in] buffer Input buffer, must not be NULL. + * @param[in] size Input buffer size, must not be 0. + * @param[out] out Output value. + */ +Result sslConnectionWrite(SslConnection *c, const void* buffer, u32 size, u32 *out); + +/** + * @brief Pending + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. + * @param c \ref SslConnection + * @param[out] out Output value. + */ +Result sslConnectionPending(SslConnection *c, s32 *out); + +/** + * @brief Peek + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. + * @param c \ref SslConnection + * @param[out] buffer Output buffer, must not be NULL. + * @param[in] size Output buffer size, must not be 0. + * @param[out] out Output value. + */ +Result sslConnectionPeek(SslConnection *c, void* buffer, u32 size, u32 *out); + +/** + * @brief Poll + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. + * @param c \ref SslConnection + * @param[in] in_pollevent Input bitmask of \ref SslPollEvent. + * @param[out] out_pollevent Output bitmask of \ref SslPollEvent. + * @param[in] timeout Timeout in milliseconds. + */ +Result sslConnectionPoll(SslConnection *c, u32 in_pollevent, u32 *out_pollevent, u32 timeout); + +/** + * @brief GetVerifyCertError + * @note The value in state is cleared after loading it. + * @param c \ref SslConnection + */ +Result sslConnectionGetVerifyCertError(SslConnection *c); + +/** + * @brief GetNeededServerCertBufferSize + * @param c \ref SslConnection + * @param[out] out Output value. + */ +Result sslConnectionGetNeededServerCertBufferSize(SslConnection *c, u32 *out); + /** * @brief SetSessionCacheMode + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. * @param c \ref SslConnection * @param[in] mode \ref SslSessionCacheMode */ Result sslConnectionSetSessionCacheMode(SslConnection *c, SslSessionCacheMode mode); +/** + * @brief GetSessionCacheMode + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. + * @param c \ref SslConnection + * @param[out] out \ref SslSessionCacheMode + */ +Result sslConnectionGetSessionCacheMode(SslConnection *c, SslSessionCacheMode *out); + +/** + * @brief GetSessionCacheMode + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. + * @param c \ref SslConnection + */ +Result sslConnectionFlushSessionCache(SslConnection *c); + /** * @brief SetRenegotiationMode + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. * @param c \ref SslConnection * @param[in] mode \ref SslRenegotiationMode */ Result sslConnectionSetRenegotiationMode(SslConnection *c, SslRenegotiationMode mode); +/** + * @brief GetRenegotiationMode + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. + * @param c \ref SslConnection + * @param[out] out \ref SslRenegotiationMode + */ +Result sslConnectionGetRenegotiationMode(SslConnection *c, SslRenegotiationMode *out); + +/** + * @brief SetOption + * @param c \ref SslConnection + * @param[in] option \ref SslOptionType + * @param[in] flag Input flag value. + */ +Result sslConnectionSetOption(SslConnection *c, SslOptionType option, bool flag); + +/** + * @brief GetOption + * @param c \ref SslConnection + * @param[in] option \ref SslOptionType + * @param[out] out Output flag value. + */ +Result sslConnectionGetOption(SslConnection *c, SslOptionType option, bool *out); + +/** + * @brief GetVerifyCertErrors + * @note An error is thrown when the cmd is successful, if the two output u32s match. + * @param[out] out0 First output value, must not be NULL. + * @param[out] out1 Second output value. + * @param[out] errors Output array of Result, must not be NULL. + * @param[in] count Size of the errors array in entries. + */ +Result sslConnectionGetVerifyCertErrors(SslConnection *c, u32 *out0, u32 *out1, Result *errors, u32 count); + +/** + * @brief GetCipherInfo + * @note Only available on [4.0.0+]. + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. + * @param c \ref SslConnection + * @param[out] out \ref SslCipherInfo + */ +Result sslConnectionGetCipherInfo(SslConnection *c, SslCipherInfo *out); + +/** + * @brief SetNextAlpnProto + * @note Only available on [9.0.0+]. + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. + * @param c \ref SslConnection + * @param[in] buffer Input buffer, must not be NULL. + * @param[in] size Input buffer size, must not be 0. Must be at least 0x2. + */ +Result sslConnectionSetNextAlpnProto(SslConnection *c, const u8* buffer, u32 size); + +/** + * @brief GetNextAlpnProto + * @note Only available on [9.0.0+]. + * @note \ref sslConnectionSetSocketDescriptor must have been used prior to this successfully. + * @param c \ref SslConnection + * @param[out] state \ref SslAlpnProtoState + * @param[out] out Output value. + * @param[out] buffer Output buffer, must not be NULL. + * @param[in] size Output buffer size, must not be 0. + */ +Result sslConnectionGetNextAlpnProto(SslConnection *c, SslAlpnProtoState *state, u32 *out, u8 *buffer, u32 size); + ///@} diff --git a/nx/source/services/ssl.c b/nx/source/services/ssl.c index 75a2db1b..7ce07221 100644 --- a/nx/source/services/ssl.c +++ b/nx/source/services/ssl.c @@ -105,6 +105,10 @@ Service* sslGetServiceSession(void) { return &g_sslSrv; } +static Result _sslCmdNoIO(Service* srv, u32 cmd_id) { + return _sslObjectDispatch(srv, cmd_id); +} + static Result _sslCmdInU32NoOut(Service* srv, u32 inval, u32 cmd_id) { return _sslObjectDispatchIn(srv, cmd_id, inval); } @@ -113,6 +117,44 @@ static Result _sslCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) { return _sslObjectDispatchOut(srv, cmd_id, *out); } +static Result _sslCmdInBufNoOut(Service* srv, const void* buffer, size_t size, u32 cmd_id) { + return _sslObjectDispatch(srv, cmd_id, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { buffer, size } }, + ); +} + +static Result _sslCmdNoInOutBufTwoOutU32s(Service* srv, u32 *out0, u32 *out1, void* buffer, size_t size, u32 cmd_id) { + struct { + u32 out0; + u32 out1; + } out; + + Result rc = _sslObjectDispatchOut(srv, cmd_id, out, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { buffer, size } }, + ); + if (R_SUCCEEDED(rc)) { + if (out0) *out0 = out.out0; + if (out1) *out1 = out.out1; + } + return rc; +} + +static Result _sslCmdInBufOutU32(Service* srv, const void* buffer, size_t size, u32 *out, u32 cmd_id) { + return _sslObjectDispatchOut(srv, cmd_id, *out, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, + .buffers = { { buffer, size } }, + ); +} + +static Result _sslCmdOutBufOutU32(Service* srv, void* buffer, size_t size, u32 *out, u32 cmd_id) { + return _sslObjectDispatchOut(srv, cmd_id, *out, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { buffer, size } }, + ); +} + Result sslCreateContext(SslContext *c, SslVersion ssl_version) { if (!serviceIsActive(&g_sslSrv)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); @@ -168,7 +210,7 @@ static Result _sslGetCertificates(void* buffer, u32 size, u32 *ca_cert_ids, u32 ); } -Result sslGetCertificates(void* buffer, u32 size, u32 *ca_cert_ids, u32 count) { +Result sslGetCertificates(void* buffer, u32 size, u32 *ca_cert_ids, u32 count, u32 *total_out) { if (buffer==NULL || !size || ca_cert_ids==NULL || !count) return MAKERESULT(Module_Libnx, LibnxError_BadInput); @@ -186,6 +228,8 @@ Result sslGetCertificates(void* buffer, u32 size, u32 *ca_cert_ids, u32 count) { } } + if (R_SUCCEEDED(rc) && total_out) *total_out = out_count; + return rc; } @@ -279,6 +323,7 @@ Result sslGetDebugOption(void* buffer, size_t size, SslDebugOptionType type) { // ISslContext void sslContextClose(SslContext *c) { + // sdknso uses sslContextGetConnectionCount here, returning the error from there on fail / throwing an error if the output count is non-zero. We won't do that. _sslObjectClose(&c->s); } @@ -394,10 +439,7 @@ Result sslContextAddPolicyOid(SslContext *c, const char* str, u32 str_bufsize) { if (str==NULL || str_bufsize > 0xff) return MAKERESULT(Module_Libnx, LibnxError_BadInput); - return _sslObjectDispatch(&c->s, 9, - .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, - .buffers = { { str, str_bufsize } }, - ); + return _sslCmdInBufNoOut(&c->s, str, str_bufsize, 9); } Result sslContextImportCrl(SslContext *c, const void* buffer, u32 size, u64 *id) { @@ -440,10 +482,7 @@ Result sslConnectionSetHostName(SslConnection *c, const char* str, u32 str_bufsi if (str==NULL) return MAKERESULT(Module_Libnx, LibnxError_BadInput); - return _sslObjectDispatch(&c->s, 1, - .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, - .buffers = { { str, str_bufsize } }, - ); + return _sslCmdInBufNoOut(&c->s, str, str_bufsize, 1); } Result sslConnectionSetVerifyOption(SslConnection *c, u32 verify_option) { @@ -474,10 +513,100 @@ Result sslConnectionGetHostName(SslConnection *c, char* str, u32 str_bufsize, u3 if (str==NULL) return MAKERESULT(Module_Libnx, LibnxError_BadInput); - return _sslObjectDispatchOut(&c->s, 5, *out, - .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, - .buffers = { { str, str_bufsize } }, - ); + return _sslCmdOutBufOutU32(&c->s, str, str_bufsize, out, 5); +} + +Result sslConnectionGetVerifyOption(SslConnection *c, u32 *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _sslCmdNoInOutU32(&c->s, out, 6); +} + +Result sslConnectionGetIoMode(SslConnection *c, SslIoMode *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + u32 tmp=0; + Result rc = _sslCmdNoInOutU32(&c->s, &tmp, 7); + if (R_SUCCEEDED(rc) && out) *out = tmp; + return rc; +} + +Result sslConnectionDoHandshake(SslConnection *c, u32 *out0, u32 *out1, void* server_certbuf, u32 server_certbuf_size) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + if (out0) *out0 = 0; + if (out1) *out1 = 0; + + if (server_certbuf==NULL || !server_certbuf_size) + return _sslCmdNoIO(&c->s, 8); // DoHandshake + + return _sslCmdNoInOutBufTwoOutU32s(&c->s, out0, out1, server_certbuf, server_certbuf_size, 9); // DoHandshakeGetServerCert +} + +Result sslConnectionRead(SslConnection *c, void* buffer, u32 size, u32 *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + if (buffer==NULL || !size) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + + return _sslCmdOutBufOutU32(&c->s, buffer, size, out, 10); +} + +Result sslConnectionWrite(SslConnection *c, const void* buffer, u32 size, u32 *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + if (buffer==NULL || !size) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + + return _sslCmdInBufOutU32(&c->s, buffer, size, out, 11); +} + +Result sslConnectionPending(SslConnection *c, s32 *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _sslCmdNoInOutU32(&c->s, (u32*)out, 12); +} + +Result sslConnectionPeek(SslConnection *c, void* buffer, u32 size, u32 *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + if (buffer==NULL || !size) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + + return _sslCmdOutBufOutU32(&c->s, buffer, size, out, 13); +} + +Result sslConnectionPoll(SslConnection *c, u32 in_pollevent, u32 *out_pollevent, u32 timeout) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + const struct { + u32 in_pollevent; + u32 timeout; + } in = { in_pollevent, timeout }; + + return _sslObjectDispatchInOut(&c->s, 14, in, *out_pollevent); +} + +Result sslConnectionGetVerifyCertError(SslConnection *c) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _sslCmdNoIO(&c->s, 15); +} + +Result sslConnectionGetNeededServerCertBufferSize(SslConnection *c, u32 *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _sslCmdNoInOutU32(&c->s, out, 16); } Result sslConnectionSetSessionCacheMode(SslConnection *c, SslSessionCacheMode mode) { @@ -487,6 +616,23 @@ Result sslConnectionSetSessionCacheMode(SslConnection *c, SslSessionCacheMode mo return _sslCmdInU32NoOut(&c->s, mode, 17); } +Result sslConnectionGetSessionCacheMode(SslConnection *c, SslSessionCacheMode *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + u32 tmp=0; + Result rc = _sslCmdNoInOutU32(&c->s, &tmp, 18); + if (R_SUCCEEDED(rc) && out) *out = tmp; + return rc; +} + +Result sslConnectionFlushSessionCache(SslConnection *c) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + return _sslCmdNoIO(&c->s, 19); +} + Result sslConnectionSetRenegotiationMode(SslConnection *c, SslRenegotiationMode mode) { if (!serviceIsActive(&c->s)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); @@ -494,3 +640,100 @@ Result sslConnectionSetRenegotiationMode(SslConnection *c, SslRenegotiationMode return _sslCmdInU32NoOut(&c->s, mode, 20); } +Result sslConnectionGetRenegotiationMode(SslConnection *c, SslRenegotiationMode *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + u32 tmp=0; + Result rc = _sslCmdNoInOutU32(&c->s, &tmp, 21); + if (R_SUCCEEDED(rc) && out) *out = tmp; + return rc; +} + +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); +} + +Result sslConnectionGetOption(SslConnection *c, SslOptionType option, bool *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + u32 tmp=option; + u8 tmpout=0; + Result rc = _sslObjectDispatchInOut(&c->s, 23, tmp, tmpout); + if (R_SUCCEEDED(rc) && out) *out = tmpout & 1; + return rc; +} + +Result sslConnectionGetVerifyCertErrors(SslConnection *c, u32 *out0, u32 *out1, Result *errors, u32 count) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + if (out0==NULL || errors==NULL) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + + if (out1) *out1 = 0; + + u32 tmp=0; + Result rc = _sslCmdNoInOutBufTwoOutU32s(&c->s, out0, &tmp, errors, count*sizeof(Result), 24); + if (R_SUCCEEDED(rc) && out1) *out1 = tmp; + if (R_SUCCEEDED(rc) && *out0 != tmp) rc = MAKERESULT(123, 112); + return rc; +} + +Result sslConnectionGetCipherInfo(SslConnection *c, SslCipherInfo *out) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + u32 tmp=1; + return _sslObjectDispatchIn(&c->s, 25, tmp, + .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out }, + .buffers = { { out, sizeof(*out) } }, + ); +} + +Result sslConnectionSetNextAlpnProto(SslConnection *c, const u8* buffer, u32 size) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + if (hosversionBefore(9,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (buffer==NULL || !size) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + + return _sslCmdInBufNoOut(&c->s, buffer, size, 26); +} + +Result sslConnectionGetNextAlpnProto(SslConnection *c, SslAlpnProtoState *state, u32 *out, u8 *buffer, u32 size) { + if (!serviceIsActive(&c->s)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + if (hosversionBefore(9,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (buffer==NULL || !size) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + + if (state) *state = SslAlpnProtoState_NoSupport; + if (out) *out = 0; + buffer[0] = 0; + + u32 tmp=0; + Result rc = _sslCmdNoInOutBufTwoOutU32s(&c->s, &tmp, out, buffer, size, 27); + if (R_SUCCEEDED(rc) && state) *state = tmp; + return rc; +} +