diff --git a/NDecrypt/N3DS/Headers/CIAHeader.cs b/NDecrypt/N3DS/Headers/CIAHeader.cs
index 3a304c4..ab1351d 100644
--- a/NDecrypt/N3DS/Headers/CIAHeader.cs
+++ b/NDecrypt/N3DS/Headers/CIAHeader.cs
@@ -101,10 +101,9 @@ namespace NDecrypt.N3DS.Headers
header.ContentSize = reader.ReadInt64();
header.CertificateChain = new Certificate[3];
- for (int i = 0; i < 3; i++)
- {
- header.CertificateChain[i] = Certificate.Read(reader);
- }
+ header.CertificateChain[0] = Certificate.Read(reader); // CA
+ header.CertificateChain[1] = Certificate.Read(reader); // Ticket
+ header.CertificateChain[2] = Certificate.Read(reader); // TMD
header.Ticket = Ticket.Read(reader, header.TicketSize);
header.TMDFileData = TitleMetadata.Read(reader, header.TMDFileSize);
diff --git a/NDecrypt/N3DS/Headers/Ticket.cs b/NDecrypt/N3DS/Headers/Ticket.cs
index f9d9bd1..fd7c5b4 100644
--- a/NDecrypt/N3DS/Headers/Ticket.cs
+++ b/NDecrypt/N3DS/Headers/Ticket.cs
@@ -149,6 +149,13 @@ namespace NDecrypt.N3DS.Headers
///
public byte[] Limits { get; private set; }
+ ///
+ /// The Content Index of a ticket has its own size defined within itself,
+ /// with seemingly a minimal of 20 bytes, the second u32 in big endian defines
+ /// the full value of X.
+ ///
+ public int ContentIndexSize { get; private set; }
+
///
/// Content Index
///
@@ -159,6 +166,14 @@ namespace NDecrypt.N3DS.Headers
///
public byte[] ContentIndex { get; private set; }
+ ///
+ /// Certificate chain
+ ///
+ ///
+ /// https://www.3dbrew.org/wiki/Ticket#Certificate_Chain
+ ///
+ public Certificate[] CertificateChain { get; set; }
+
///
/// Read from a stream and get ticket, if possible
///
@@ -214,9 +229,17 @@ namespace NDecrypt.N3DS.Headers
tk.Audit = reader.ReadByte();
tk.Reserved6 = reader.ReadBytes(0x42);
tk.Limits = reader.ReadBytes(0x40);
+ reader.ReadBytes(4);
+ tk.ContentIndexSize = reader.ReadInt32();
+ reader.BaseStream.Seek(-8, SeekOrigin.Current);
+ tk.ContentIndex = reader.ReadBytes(tk.ContentIndexSize);
- if (ticketSize - 0x164 > 0)
- tk.ContentIndex = reader.ReadBytes(ticketSize - 0x164);
+ if (ticketSize - (0x164 + tk.ContentIndexSize) > 0)
+ {
+ tk.CertificateChain = new Certificate[2];
+ tk.CertificateChain[0] = Certificate.Read(reader); // Ticket
+ tk.CertificateChain[1] = Certificate.Read(reader); // CA
+ }
return tk;
}
diff --git a/NDecrypt/N3DS/Headers/TitleMetadata.cs b/NDecrypt/N3DS/Headers/TitleMetadata.cs
index 5162b01..f52983b 100644
--- a/NDecrypt/N3DS/Headers/TitleMetadata.cs
+++ b/NDecrypt/N3DS/Headers/TitleMetadata.cs
@@ -136,6 +136,14 @@ namespace NDecrypt.N3DS.Headers
///
public ContentChunkRecord[] ContentChunkRecords { get; private set; }
+ ///
+ /// Certificate chain
+ ///
+ ///
+ /// https://www.3dbrew.org/wiki/Title_metadata#Certificate_Chain
+ ///
+ public Certificate[] CertificateChain { get; set; }
+
///
/// Read from a stream and get ticket metadata, if possible
///
@@ -203,6 +211,13 @@ namespace NDecrypt.N3DS.Headers
tm.ContentChunkRecords[i] = ContentChunkRecord.Read(reader);
}
+ if (metadataSize - (0xC4 + (64 * 0x24) + (tm.ContentCount * 0x30)) > 0)
+ {
+ tm.CertificateChain = new Certificate[2];
+ tm.CertificateChain[0] = Certificate.Read(reader); // TMD
+ tm.CertificateChain[1] = Certificate.Read(reader); // CA
+ }
+
return tm;
}
catch