diff --git a/Ryujinx.HLE/HOS/Services/Ssl/BuiltInCertificateManager.cs b/Ryujinx.HLE/HOS/Services/Ssl/BuiltInCertificateManager.cs index 70691e1b..a164c745 100644 --- a/Ryujinx.HLE/HOS/Services/Ssl/BuiltInCertificateManager.cs +++ b/Ryujinx.HLE/HOS/Services/Ssl/BuiltInCertificateManager.cs @@ -181,7 +181,11 @@ namespace Ryujinx.HLE.HOS.Services.Ssl } } - public bool TryGetCertificates(ReadOnlySpan ids, out CertStoreEntry[] entries) + public bool TryGetCertificates( + ReadOnlySpan ids, + out CertStoreEntry[] entries, + out bool hasAllCertificates, + out int requiredSize) { lock (_lock) { @@ -190,7 +194,8 @@ namespace Ryujinx.HLE.HOS.Services.Ssl throw new InvalidSystemResourceException(CertStoreTitleMissingErrorMessage); } - bool hasAllCertificates = false; + requiredSize = 0; + hasAllCertificates = false; foreach (CaCertificateId id in ids) { @@ -205,12 +210,14 @@ namespace Ryujinx.HLE.HOS.Services.Ssl if (hasAllCertificates) { entries = new CertStoreEntry[_certificates.Count]; + requiredSize = (_certificates.Count + 1) * Unsafe.SizeOf(); int i = 0; foreach (CertStoreEntry entry in _certificates.Values) { entries[i++] = entry; + requiredSize += (entry.Data.Length + 3) & ~3; } return true; @@ -218,6 +225,7 @@ namespace Ryujinx.HLE.HOS.Services.Ssl else { entries = new CertStoreEntry[ids.Length]; + requiredSize = ids.Length * Unsafe.SizeOf(); for (int i = 0; i < ids.Length; i++) { @@ -227,6 +235,7 @@ namespace Ryujinx.HLE.HOS.Services.Ssl } entries[i] = entry; + requiredSize += (entry.Data.Length + 3) & ~3; } return true; diff --git a/Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs b/Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs index d397ef5b..73f04441 100644 --- a/Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs +++ b/Ryujinx.HLE/HOS/Services/Ssl/ISslService.cs @@ -29,42 +29,40 @@ namespace Ryujinx.HLE.HOS.Services.Ssl return ResultCode.Success; } - private uint ComputeCertificateBufferSizeRequired(ReadOnlySpan entries) - { - uint totalSize = 0; - - for (int i = 0; i < entries.Length; i++) - { - totalSize += (uint)Unsafe.SizeOf(); - totalSize += (uint)entries[i].Data.Length; - } - - return totalSize; - } - [CommandHipc(2)] // GetCertificates(buffer ids) -> (u32 certificates_count, buffer certificates) public ResultCode GetCertificates(ServiceCtx context) { ReadOnlySpan ids = MemoryMarshal.Cast(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size)); - if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out BuiltInCertificateManager.CertStoreEntry[] entries)) + if (!BuiltInCertificateManager.Instance.TryGetCertificates( + ids, + out BuiltInCertificateManager.CertStoreEntry[] entries, + out bool hasAllCertificates, + out int requiredSize)) { throw new InvalidOperationException(); } - if (ComputeCertificateBufferSizeRequired(entries) > context.Request.ReceiveBuff[0].Size) + 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 rawData = region.Memory.Span; - Span infos = MemoryMarshal.Cast(rawData)[..entries.Length]; - Span certificatesData = rawData[(Unsafe.SizeOf() * entries.Length)..]; + Span infos = MemoryMarshal.Cast(rawData)[..infosCount]; + Span certificatesData = rawData[(Unsafe.SizeOf() * infosCount)..]; - for (int i = 0; i < infos.Length; i++) + for (int i = 0; i < entries.Length; i++) { entries[i].Data.CopyTo(certificatesData); @@ -78,6 +76,17 @@ namespace Ryujinx.HLE.HOS.Services.Ssl 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); @@ -91,12 +100,12 @@ namespace Ryujinx.HLE.HOS.Services.Ssl { ReadOnlySpan ids = MemoryMarshal.Cast(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size)); - if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out BuiltInCertificateManager.CertStoreEntry[] entries)) + if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out _, out _, out int requiredSize)) { throw new InvalidOperationException(); } - context.ResponseData.Write(ComputeCertificateBufferSizeRequired(entries)); + context.ResponseData.Write(requiredSize); return ResultCode.Success; }