Files
Kenji-NX/src/Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs
T
Coxxs 5f40a22b0d HLE: Implement CreateContextForSystem
Implement nn::ssl::sf::ISslServiceForSystem -> CreateContextForSystem (100)

Ryujinx implements both ISslService and ISslServiceForSystem in one class so we can just return new ISslContext.

Also fixed the incorrect parameter reading order. (CreateContextForSystem basically has same params as CreateContext)
2026-03-14 23:00:03 -05:00

176 lines
6.8 KiB
C#

using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Services.Ssl.SslService;
using Ryujinx.HLE.HOS.Services.Ssl.Types;
using Ryujinx.Memory;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Ssl
{
[Service("ssl")]
[Service("ssl:s")]
class ISslService : IpcService
{
// NOTE: The SSL service is used by games to connect it to various official online services, which we do not intend to support.
// In this case it is acceptable to stub all calls of the service.
public ISslService(ServiceCtx context) { }
[CommandCmif(0)]
// CreateContext(nn::ssl::sf::SslVersion, u64 pid_placeholder, pid) -> object<nn::ssl::sf::ISslContext>
public ResultCode CreateContext(ServiceCtx context)
{
SslVersion sslVersion = (SslVersion)context.RequestData.ReadUInt32();
#pragma warning disable IDE0059 // Remove unnecessary value assignment
ulong pidPlaceholder = context.RequestData.ReadUInt64();
#pragma warning restore IDE0059
MakeObject(context, new ISslContext(context.Request.HandleDesc.PId, sslVersion));
Logger.Stub?.PrintStub(LogClass.ServiceSsl, new { sslVersion });
return ResultCode.Success;
}
[CommandCmif(2)]
// GetCertificates(buffer<CaCertificateId, 5> ids) -> (u32 certificates_count, buffer<bytes, 6> certificates)
public ResultCode GetCertificates(ServiceCtx context)
{
ReadOnlySpan<CaCertificateId> ids = MemoryMarshal.Cast<byte, CaCertificateId>(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size));
if (!BuiltInCertificateManager.Instance.TryGetCertificates(
ids,
out BuiltInCertificateManager.CertStoreEntry[] entries,
out bool hasAllCertificates,
out int requiredSize))
{
throw new InvalidOperationException();
}
if ((uint)requiredSize > (uint)context.Request.ReceiveBuff[0].Size)
{
return ResultCode.InvalidCertBufSize;
}
int infosCount = entries.Length;
if (hasAllCertificates)
{
infosCount++;
}
using (WritableRegion region = context.Memory.GetWritableRegion(context.Request.ReceiveBuff[0].Position, (int)context.Request.ReceiveBuff[0].Size))
{
Span<byte> rawData = region.Memory.Span;
Span<BuiltInCertificateInfo> infos = MemoryMarshal.Cast<byte, BuiltInCertificateInfo>(rawData)[..infosCount];
Span<byte> certificatesData = rawData[(Unsafe.SizeOf<BuiltInCertificateInfo>() * infosCount)..];
for (int i = 0; i < entries.Length; i++)
{
entries[i].Data.CopyTo(certificatesData);
infos[i] = new BuiltInCertificateInfo
{
Id = entries[i].Id,
Status = entries[i].Status,
CertificateDataSize = (ulong)entries[i].Data.Length,
CertificateDataOffset = (ulong)(rawData.Length - certificatesData.Length),
};
certificatesData = certificatesData[entries[i].Data.Length..];
}
if (hasAllCertificates)
{
infos[entries.Length] = new BuiltInCertificateInfo
{
Id = CaCertificateId.All,
Status = TrustedCertStatus.Invalid,
CertificateDataSize = 0,
CertificateDataOffset = 0,
};
}
}
context.ResponseData.Write(entries.Length);
return ResultCode.Success;
}
[CommandCmif(3)]
// GetCertificateBufSize(buffer<CaCertificateId, 5> ids) -> u32 buffer_size;
public ResultCode GetCertificateBufSize(ServiceCtx context)
{
ReadOnlySpan<CaCertificateId> ids = MemoryMarshal.Cast<byte, CaCertificateId>(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size));
if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out _, out _, out int requiredSize))
{
throw new InvalidOperationException();
}
context.ResponseData.Write(requiredSize);
return ResultCode.Success;
}
[CommandCmif(5)]
// SetInterfaceVersion(u32)
public ResultCode SetInterfaceVersion(ServiceCtx context)
{
// 1 = 3.0.0+, 2 = 5.0.0+, 3 = 6.0.0+
uint interfaceVersion = context.RequestData.ReadUInt32();
Logger.Stub?.PrintStub(LogClass.ServiceSsl, new { interfaceVersion });
return ResultCode.Success;
}
[CommandCmif(100)]
// CreateContextForSystem(nn::ssl::sf::SslVersion, u64 pid_placeholder, pid) -> object<nn::ssl::sf::ISslContextForSystem>
public ResultCode CreateContextForSystem(ServiceCtx context)
{
SslVersion sslVersion = (SslVersion)context.RequestData.ReadUInt32();
#pragma warning disable IDE0059 // Remove unnecessary value assignment
ulong pidPlaceholder = context.RequestData.ReadUInt64();
#pragma warning restore IDE0059
// Note: We use ISslContext here instead of ISslContextForSystem class because Ryujinx implements both in one class.
MakeObject(context, new ISslContext(context.Request.HandleDesc.PId, sslVersion));
Logger.Stub?.PrintStub(LogClass.ServiceSsl, new { sslVersion });
return ResultCode.Success;
}
[CommandCmif(101)]
// SetThreadCoreMask(u64 mask)
public ResultCode SetThreadCoreMask(ServiceCtx context)
{
ulong mask = context.RequestData.ReadUInt64();
Logger.Stub?.PrintStub(LogClass.ServiceSsl, new { mask });
return ResultCode.Success;
}
[CommandCmif(102)]
// GetThreadCoreMask() -> u64
public ResultCode GetThreadCoreMask(ServiceCtx context)
{
Logger.Stub?.PrintStub(LogClass.ServiceSsl);
return ResultCode.Success;
}
[CommandCmif(103)]
// VerifySignature(buffer<0x5> unknownInput1, buffer<0x5> unknownInput2, buffer<0x5> unknownInput3, buffer<bytes, 4> unknown1)
public ResultCode VerifySignature(ServiceCtx context)
{
// I would log these values like a proper stub, but I genuinely don't know how.
Logger.Stub?.PrintStub(LogClass.ServiceSsl);
return ResultCode.Success;
}
}
}