Certified File: Difference between revisions

From PS3 Developer wiki
Jump to navigation Jump to search
 
(20 intermediate revisions by 3 users not shown)
Line 1: Line 1:
Certified Files are the most common encrypted files on SCE PlayStation devices since PSP.
Certified Files are the most common encrypted files on PS3 and PS Vita.


= Introduction =
= Introduction =
Line 5: Line 5:
Not only ELF/PRX files can be signed with this format, other known Certified Files are:
Not only ELF/PRX files can be signed with this format, other known Certified Files are:
* revoke list
* revoke list
* security policy profile
* PS3 security policy profile
* system software package (e.g. .pkg, .spkg_hdr.X)
* system software package (.pkg)
* system software package header (.spkg_hdr.X)
* PS Vita diff file (never met such a file yet)
* PS Vita game cartridge param.sfo (gro0:gc/param.sfo)
* PS Vita launch list (SPKG with filename extension .dat)


= Structure =
= Structure =


It is important to notice that PS3 use big endian whilst PSVita use little endian.
It is important to notice that PS3 uses big-endian whilst PS Vita uses little-endian.


== Header ==
== Header ==
Line 16: Line 20:
<source lang="C">
<source lang="C">
typedef struct { // Size is 0x20 for v2, 0x30 for v3
typedef struct { // Size is 0x20 for v2, 0x30 for v3
  uint32_t magic;
uint32_t magic;
  uint32_t version;
uint32_t version;
  uint16_t attribute;
uint16_t attribute;
  uint16_t category;
uint16_t category;
  uint32_t ext_header_size;
uint32_t ext_header_size;
  uint64_t file_offset;
uint64_t file_offset;
  uint64_t file_size;
uint64_t file_size;
  union {
union {
      uint64_t cf_file_size;
struct {
      uint64_t unknown;
uint64_t cf_file_size;
  };
uint64_t padding;
};
};
} __attribute__((packed)) cf_header;
} __attribute__((packed)) cf_header;
</source>
</source>
Line 35: Line 41:
| Magic || 0x0 || u32 || Must be "SCE\0".
| Magic || 0x0 || u32 || Must be "SCE\0".
|-
|-
| Version || 0x4 || u32 || 2 for PS3, 3 for PSVita.
| Version || 0x4 || u32 || 2 for PS3, 3 for PS Vita.
|-
|-
| Attribute || 0x8  || u16|| Corresponds to the revision of the enc/dec key. See [https://www.psdevwiki.com/ps3/Revision_versus_Version Attribute].
| Attribute || 0x8  || u16 || Corresponds to the revision of the encryption key. The [[Certified File Key ID]] is derived from the attribute.
|-
|-
| Category || 0xA || u16 || See [[Certified_File#Category|Category]].
| Category || 0xA || u16 || See [[Certified_File#Category|Category]].
|-
|-
| Extended Header size || 0xC || u32 || For SELF category only, set to 0 for other categories. See Extended Header.
| Extended Header size || 0xC || u32 || For SELF category only, set to 0 for other categories. See [[SELF_-_SPRX#Segment_Extended_Header]].
|-
|-
| File offset || 0x10  || u64 || Offset to encapsulated data.
| File offset || 0x10  || u64 || Offset to encapsulated data.
Line 49: Line 55:
| CF file size || 0x20 || u64 || Size of the CF file. Present on version 3 only.
| CF file size || 0x20 || u64 || Size of the CF file. Present on version 3 only.
|-
|-
| unknown || 0x28 || u64 || Maybe padding. Set to 0. Present on version 3 only.
| Padding || 0x28 || u64 || Padding. Set to 0. Present on version 3 only.
|}
|}


Line 57: Line 63:
! Value !! Type !! Name !! Remark
! Value !! Type !! Name !! Remark
|-
|-
| 1 || SELF - SPRX || signed-elf - signed-prx || Used for storing ELF and PRX.
| 1 || SELF - SPRX || signed-elf - signed-prx || Used for storing ELF and PRX. Both PS3 and PS Vita.
|-
| 2 || SRVK || signed-revoke-list || Used for [[Revokation]]. Both PS3 and PS Vita.
|-
| 3 || SPKG || signed-package || Used for [[PKG_files#Firmware_Packages|System Software Packages]]. Both PS3 and PS Vita.
|-
|-
| || SRVK || signed-revoke-list || Used for [[Revokation]].
| 4 || SSPP || signed-security-policy-profile || The only file of this category is [[Default.spp]]. PS3 only.
|-
|-
| || SPKG || signed-package || Used for [[PKG_files#Firmware_Packages|System Software Packages]].
| 5 || SDIFF || signed-diff || Used in Prototype PS Vita Applier module. PS Vita only. No sample file available.
|-
|-
| || SSPP || signed-security-policy-profile || The only file of this category is [[Default.spp]] on PS3.
| 6 || SPSFO || signed-param-sfo || Spsfo (signed param.sfo) file is located in game cartridge at path gro0:gc/param.sfo. PS Vita only.
|}
|}


== Encryption Root Header ==
== Encryption Root Header ==


Temp name was Metadata Information. Official name is encryption_root_header.
Temporary name was Metadata Information. Official name is encryption_root_header.


This is not present in fCF (fSELF, fSPP, etc...).
Encryption Root Header is not present in fCF (fSELF, fSPP, etc...).


The key and ivec fields are encrypted using AES256CBC.
Encryption Root Header is decrypted using AES256CBC with the key and iv from System Software.


=== Struct ===
=== Struct ===
Line 78: Line 88:
<source lang="C">
<source lang="C">
typedef struct {
typedef struct {
  uint8_t key[16];
uint8_t key[16];
  uint8_t key_pad[16];
uint8_t key_pad[16];
  uint8_t iv[16];
uint8_t iv[16];
  uint8_t iv_pad[16];
uint8_t iv_pad[16];
} __attribute__((packed)) encryption_root_header;
} __attribute__((packed)) cf_encryption_root_header;
</source>
</source>


Line 89: Line 99:
== Certification Header ==
== Certification Header ==


Temp name was Metadata Header. Official name is certification_header.
Temporary name was Metadata Header. Official name is certification_header.
 
It is only present if the Encryption Root Header is present.


It is decrypted using AES128 with the key and ivec entries from the Encryption Root Header.
Certification Header is only present if the Encryption Root Header is present. In that case, Certification Header is located after the Encryption Root Header.


It is located after the Encryption Root Header in the SELF file.
Certification Header is decrypted using AES128 with the key and iv entries from the Encryption Root Header.


=== Struct ===
=== Struct ===
Line 101: Line 109:
<source lang="C">
<source lang="C">
typedef struct {
typedef struct {
  uint64_t footer_offset;
uint64_t sign_offset;
  uint32_t signature_type;            // 1 = ECDSA160, 5 = RSA2048
uint32_t sign_algorithm;            // 1 = ECDSA160, 2 = HMACSHA1, 3 = SHA1, 5 = RSA2048, 6 = HMACSHA256 (?not used?)
  uint32_t segment_count;
uint32_t cert_entry_num;
  uint32_t blocks_count; // was keyCount
uint32_t attr_entry_num;
  uint32_t optional_header_size;
uint32_t optional_header_size;
  uint64_t unknown06;
uint64_t pad;
} __attribute__((packed)) certification_header;
} __attribute__((packed)) cf_certification_header;
</source>
</source>


Line 114: Line 122:
== Certification Body ==
== Certification Body ==


*It is decrypted with the key and ivec entries from the Encryption Root Header.
Certification Body is located just after the Certification Header.
 
Certification Body is decrypted using AES128 with the key and iv entries from the Encryption Root Header.


=== Segment Certification Header ===
=== Segment Certification Header ===


Temp name was Metadata Section Header. Official name is segment_certification_header.
Temporary name was Metadata Section Header. Official name is segment_certification_header.


It is only present if the Certification Header is present.
Segment Certification Header is only present if the Certification Header is present.


The number of sections is indicated by the segment_count entry in the Certification Header.
The number of Segment Certification Headers is indicated by the cert_entry_num field in the Certification Header.


The Segment Certification Headers are located after the Certification Header in the SELF file.
Segment Certification Header is located after the Certification Header.


==== Struct ====
==== Struct ====
Line 130: Line 140:
<source lang="C">
<source lang="C">
typedef struct {
typedef struct {
  uint64_t segment_offset;
uint64_t segment_offset;
  uint64_t segment_size;
uint64_t segment_size;
  uint32_t segment_type;   // 1 = shdr, 2 = phdr, 3 = sceversion
uint32_t segment_type;     // 1 = shdr, 2 = phdr, 3 = sceversion
  uint32_t program_idx;   // 0,1,2,3,etc for phdr, always 3 for shdrs, sceversion shdr number for sceversion
uint32_t segment_id;       // 0,1,2,3,etc for phdr, always 3 for shdrs, sceversion shdr number for sceversion
  uint32_t hash_algorithm; // ?1 = none?, 2 = sha1_hmac, 3 = sha1, 6 = sha256_hmac
uint32_t sign_algorithm;   // 1 = ECDSA160 (not used), 2 = HMACSHA1, 3 = SHA1, 5 = RSA2048 (not used), 6 = HMACSHA256
  uint32_t hash_idx;
uint32_t sign_idx;
  uint32_t enc_algorithm; // 1 = none, 2 = aes128cbccfb, 3 = aes128ctr
uint32_t enc_algorithm;     // 1 = none, 2 = aes128cbccfb, 3 = aes128ctr
  uint32_t key_idx;       // -1 when enc_algorithm = none
uint32_t key_idx;           // -1 when enc_algorithm = none
  uint32_t iv_idx;         // -1 when enc_algorithm = none
uint32_t iv_idx;           // -1 when enc_algorithm = none
  uint32_t comp_algorithm; // 1 = none, 2 = zlib
uint32_t comp_algorithm;   // 1 = plain, 2 = zlib
} __attribute__((packed)) segment_certification_header;
} __attribute__((packed)) cf_segment_certification_header;
</source>
</source>


==== Comments ====
==== Comments ====


Notes:
* Segment data is decrypted using enc_algorithm with the key and iv specified by key_idx and iv_idx, in the Attributes.
*Segment data is decrypted using enc_algorithm with the key and ivec from the Segment Certification specified by key_idx and iv_idx.
* The segment_offset field in the Segment Certification Header usually matches the offset field in the [[SELF_-_SPRX#Segment_Extended_Header|Segment Extended Header]].
*The segment_offset of the Segment Certification Header matches in general the offset from the Segment Extended Header.


=== Segment Certification ===
=== Attributes ===


Temp name was Metadata Keys, Section Hash. Official name might be Segment Certification.
Temporary name was Metadata Keys, Section Hash, Segment Certification. Official name is attribute(s), found sub get_attribute(unsigned char *, unsigned int) on spp_verifier which returns pointer to signature/key/iv by its id.


The number of Segment Certifications is indicated by the segment_count entry in the Certification Header.
The number of Attributes is indicated by the attr_entry_num field in the Certification Header.


The Segment Certifications are located after the Segment Certification Headers in the SELF file.
Attributes are located after the Segment Certification Headers.


==== Struct ====
==== Struct ====


<source lang="C">
<source lang="C">
typedef struct {
typedef struct {
  union { // size is 0x40 bytes
union { // size is 0x60 bytes
    uint8_t digest[0x20]; // hmac_sha1
uint8_t signature[0x20]; // hmac_sha1_hash
    uint8_t hmac_key[0x20];
uint8_t sign_key[0x40];
  } hash_type2;
} signature_type2;
  union { // size is 0x60 bytes
union { // size is 0x20 bytes
    uint8_t unk0[0x20]; // certinly hmax_sha256
uint8_t signature[0x20]; // sha1_hash
    uint8_t unk1[0x40]; // certainly hmac_key
} signature_type3;
  } hash_type6;
union { // size is 0x40 bytes
  union { // size is 0x20 bytes
uint8_t signature[0x20]; // hmac_sha256_hash
    uint8_t key[0x10];
uint8_t sign_key[0x20];
    uint8_t iv[0x10];
} signature_type6;
  } encryption_params; // present for type 2 and 3
union { // size is 0x20 bytes
} __attribute__((packed)) segment_certification;
uint8_t key[0x10];
uint8_t iv[0x10];
} encryption_params; // present for enc_algorithm type 2 and 3
} __attribute__((packed)) cf_attribute;
</source>
</source>


==== Comments ====
==== Comments ====


Notes:
* The signature is calculated on the decrypted data and before the decompression.
*The HMAC-SHA1 is calculated on the decrypted data and before the decompression.


=== Optional Header Table ===
=== Optional Header Table ===


Temp name was Signature Info, Capabilities Info. Official name is optional_header_table.
Temporary name was Signature Info, Capabilities Info. Official name is optional_header_table.


The Optional Header Table is located after the Section Hash in the SELF file.
Optional Header Table is only present if optional_header_size in the Certification Header is not zero. In that case, Optional Header Table is located after the Attributes.
It is only present if optional_header_size in the Certification Header is not zero.


==== Struct ====
==== Struct ====
Line 195: Line 204:
uint32_t type; // 1=capability_header, 2=individual_seed_header, 3=attribute_header
uint32_t type; // 1=capability_header, 2=individual_seed_header, 3=attribute_header
uint32_t size;
uint32_t size;
uint64_t next; // 1 if another optional_header structure follows else 0
uint64_t next; // 1 if another cf_optional_header structure follows else 0
union {
union {
// type 1
// type 1
Line 210: Line 219:
} attribute_header;
} attribute_header;
};
};
} __attribute__((packed)) optional_header;
} __attribute__((packed)) cf_optional_header;
</source>
</source>


=== Comments ===
==== Comments ====


* Type 1 contains encrypted_capability. See [[Capability Flags]].
* Optional Header Type 1 contains encrypted_capability (not plaintext capability). See [[Capability Flags]].


== Certification Footer ==
== Signature ==


Temp name was Signature.
Official name might be Signature.


It is located at the Certification Header footer_offset in the SELF file.
Signature is located at the Certification Header sign_offset in the Certified File.


It is decrypted with the key and ivec entries from the Encryption Root Header.
Signature is decrypted with the key and iv entries from the Encryption Root Header.


It can be ECDSA160 or RSA2048, according to the Certification Header.
Signature algorithm can be ECDSA160 or RSA2048, according to the Certification Header.


=== Struct ===
=== Struct ===
Line 231: Line 240:
<source lang="C">
<source lang="C">
typedef struct {
typedef struct {
  union {
union {
    uint8_t r[21];
uint8_t r[21];
    uint8_t s[21];
uint8_t s[21];
    uint8_t padding[6];
uint8_t padding[6];
  } ECDSA160;
} ECDSA160;
  union {
union {
    uint8_t rsa[0x100];
uint8_t rsa[0x100];
  } RSA2048;
} RSA2048;
} __attribute__((packed)) certification_footer;
} __attribute__((packed)) cf_signature;
</source>
</source>


=== Comments ===
=== Comments ===


* footer_offset is the number of bytes which are used to generate the SHA-1 which is used to generate the ECDSA signature. The length should be eveything from the beginning until the signature itself. The decrypted version of the input data is used for signature.
* sign_offset is the size of the data on which is computed the signature, from the start of the Certified File. The decrypted version of the input data is used for signature.


= Decryption =
= Decryption =


Certified Files are all encrypted using the exact same algorithm. SELF are hashed and signed (signature is RSA based at the very least since firmware 0.940). This section only focuses on the encryption layer itself.
Certified Files are all encrypted using the exact same algorithm (except for Fake Certified Files). They can be encrypted, hashed and signed. This section only focuses on the encryption layer.
 
* Step 0: Get Encryption Root Header Master Keys
 
On PS3, TO DOCUMENT.
 
On PS Vita, static key and IV are contained within the relevant Secure Module. For example, SPKG keys are located in update_service_sm.self, KPRX keys are located in kprx_auth_sm.self, Security Modules keys and kernel_boot_loader.self keys are located in secure_kernel.


* Step 1: Get SELF metadata decryption key and IV
* Step 1: Get Encryption Root Key and IV


Get a static key and IV contained within the relevant Secure Module. For example Update Package keys are located in update_service_sm.self, kernel PRX keys are located in kprx_auth_sm.self, Secure Modules (SM) as well as kernel_boot_loader.self, are located in secure_kernel.enp).
Decrypt the Certification Header using AES256CBC on PS Vita (to document for PS3).


Decrypt the first 0x40 bytes of the SELF metadata using AES256CBC.
This results into the key and IV used in step 2.


This results into the key and IV used in step 2
* Step 2: Get plain Certification


* Step 2: Get plain SELF metadata
Use the key and IV decrypted from the Encryption Root Header to decrypt the Certification using AES128CBC on PS Vita (what on PS3?).


Use the key and IV decrypted from the first 0x40 bytes of the SELF metadata to decrypt the rest of the SELF metadata using AES128-CBC.
* Step 3: Parse Certification


* Step 3: Parse SELF metadata
SELF Certification is typically stored in the following format. Below is an example of a 4-segments PS Vita SELF.


The SELF metadata is typically stored in this format (below is the metadata example for a 4 sections self):
SPKG Certification follows the same principles but is slightly different (different Magic/Header).
The SPKG metadata follows the same principles but is slightly different (different MAGIC/Header).


<source lang = "C">
<source lang = "C">
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F


00000000  F0 07 00 00 00 00 00 00 05 00 00 00 04 00 00 00  ð............... <<< Metadata header (0x20 long) ;  metasize (u64), signature type (u32) number of sections (u32) // Sig type 5 = RSA
00000000  F0 07 00 00 00 00 00 00 05 00 00 00 04 00 00 00  ð............... <<< Certification Header
00000010  18 00 00 00 70 01 00 00 00 00 00 00 00 00 00 00  ....p...........
00000010  18 00 00 00 70 01 00 00 00 00 00 00 00 00 00 00  ....p........... <<< Certification Header
00000020  00 0A 00 00 00 00 00 00 C0 00 00 00 00 00 00 00  ........À....... <<< First section address
00000020  00 0A 00 00 00 00 00 00 C0 00 00 00 00 00 00 00  ........À....... <<< First segment address
00000030  02 00 00 00 01 00 00 00 06 00 00 00 00 00 00 00  ................
00000030  02 00 00 00 01 00 00 00 06 00 00 00 00 00 00 00  ................
00000040  03 00 00 00 04 00 00 00 05 00 00 00 01 00 00 00  ................
00000040  03 00 00 00 04 00 00 00 05 00 00 00 01 00 00 00  ................
00000050  00 0B 00 00 00 00 00 00 FC B4 07 00 00 00 00 00  ........ü´...... <<< First section address
00000050  00 0B 00 00 00 00 00 00 FC B4 07 00 00 00 00 00  ........ü´...... <<< Second segment address
00000060  02 00 00 00 02 00 00 00 06 00 00 00 06 00 00 00  ................
00000060  02 00 00 00 02 00 00 00 06 00 00 00 06 00 00 00  ................
00000070  03 00 00 00 0A 00 00 00 0B 00 00 00 01 00 00 00  ................
00000070  03 00 00 00 0A 00 00 00 0B 00 00 00 01 00 00 00  ................
00000080  00 C0 07 00 00 00 00 00 98 1E 00 00 00 00 00 00  .À......˜....... <<< First section address
00000080  00 C0 07 00 00 00 00 00 98 1E 00 00 00 00 00 00  .À......˜....... <<< Third segment address
00000090  02 00 00 00 03 00 00 00 06 00 00 00 0C 00 00 00  ................
00000090  02 00 00 00 03 00 00 00 06 00 00 00 0C 00 00 00  ................
000000A0  03 00 00 00 10 00 00 00 11 00 00 00 01 00 00 00  ................
000000A0  03 00 00 00 10 00 00 00 11 00 00 00 01 00 00 00  ................
000000B0  00 DF 07 00 00 00 00 00 9D BA 02 00 00 00 00 00  .ß.......º...... <<< Fourth section address
000000B0  00 DF 07 00 00 00 00 00 9D BA 02 00 00 00 00 00  .ß.......º...... <<< Fourth segment address
000000C0  02 00 00 00 04 00 00 00 06 00 00 00 12 00 00 00  ................
000000C0  02 00 00 00 04 00 00 00 06 00 00 00 12 00 00 00  ................
000000D0  03 00 00 00 16 00 00 00 17 00 00 00 01 00 00 00  ................
000000D0  03 00 00 00 16 00 00 00 17 00 00 00 01 00 00 00  ................
000000E0  AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªªªªªª  <<< First Section Hash
000000E0  AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªªªªªª  <<< First segment Hash
000000F0  AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªªªªªª  <<< First Section Hash
000000F0  AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªªªªªª  <<< First segment Hash
00000100  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
00000100  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
00000110  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
00000110  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
00000120  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< First Section random key
00000120  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< First segment random key
00000130  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< First Section random IV
00000130  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< First segment random IV
00000140  BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB  »»»»»»»»»»»»»»»»  <<< Second Section Hash
00000140  BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB  »»»»»»»»»»»»»»»»  <<< Second segment Hash
00000150  BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB  »»»»»»»»»»»»»»»»  <<< Second Section Hash
00000150  BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB  »»»»»»»»»»»»»»»»  <<< Second segment Hash
00000160  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
00000160  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
00000170  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
00000170  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
00000180  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Second Section random key
00000180  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Second segment random key
00000190  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Second Section random IV
00000190  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Second segment random IV
000001A0  CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC  ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ  <<< Third Section Hash
000001A0  CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC  ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ  <<< Third segment Hash
000001B0  CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC  ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ  <<< Third Section Hash
000001B0  CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC  ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ  <<< Third segment Hash
000001C0  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
000001C0  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
000001D0  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
000001D0  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
000001E0  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Third Section random key
000001E0  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Third segment random key
000001F0  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Third Section random IV
000001F0  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Third segment random IV
00000200  DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD  ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ  <<< Fourth Section Hash
00000200  DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD  ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ  <<< Fourth segment Hash
00000210  DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD  ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ  <<< Fourth Section Hash
00000210  DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD  ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ  <<< Fourth segment Hash
00000220  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
00000220  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
00000230  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
00000230  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
00000240  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Fourth Section random key
00000240  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Fourth segment random key
00000250  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Fourth Section random IV
00000250  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Fourth segment random IV
00000260  01 00 00 00 30 00 00 00 01 00 00 00 00 00 00 00  ....0...........  <<< type (u32), section size (u32), isMoreSections (u32)
00000260  01 00 00 00 30 00 00 00 01 00 00 00 00 00 00 00  ....0...........  <<< type (u32), segment size (u32), isMoreSegments (u32)
00000270  80 00 00 00 C0 00 F0 00 00 00 00 00 FF FF FF FF  €...À.ð.....ÿÿÿÿ  
00000270  80 00 00 00 C0 00 F0 00 00 00 00 00 FF FF FF FF  €...À.ð.....ÿÿÿÿ  
00000270  80 00 00 00 C0 00 F0 00 00 00 00 00 FF FF FF FF  €...À.ð.....ÿÿÿÿ
00000270  80 00 00 00 C0 00 F0 00 00 00 00 00 FF FF FF FF  €...À.ð.....ÿÿÿÿ
00000280  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000280  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000290  02 00 00 00 10 01 00 00 01 00 00 00 00 00 00 00  ................  <<< type (u32), section size (u32), isMoreSections (u32)
00000290  02 00 00 00 10 01 00 00 01 00 00 00 00 00 00 00  ................  <<< type (u32), segment size (u32), isMoreSegments (u32)
000002A0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000002A0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000002B0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000002B0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
Line 329: Line 343:
00000380  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000380  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000390  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000390  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000003A0  03 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00  ....0...........  <<< type (u32), section size (u32), isMoreSections (u32)
000003A0  03 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00  ....0...........  <<< type (u32), segment size (u32), isMoreSegments (u32)
000003B0  80 09 80 03 00 00 C3 00 00 00 80 09 80 00 00 00  €.€...Ã...€.€...
000003B0  80 09 80 03 00 00 C3 00 00 00 80 09 80 00 00 00  €.€...Ã...€.€...
000003C0  00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF  ............ÿÿÿÿ
000003C0  00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF  ............ÿÿÿÿ
000003D0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
000003D0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000003E0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
000003E0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000003F0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
000003F0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000400  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000400  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000410  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000410  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000420  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000420  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000430  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000430  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000440  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000440  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000450  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000450  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000460  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000460  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000470  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000470  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000480  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000480  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000490  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000490  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000004A0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
000004A0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000004B0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
000004B0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000004C0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
000004C0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000004D0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................  <<< Metadata end
000004D0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................  <<< Certification Body end, padding
</source>
</source>


Following the same principles, an update package metadata would look like this:  
Following the same principles, a plain SPKG Certification Body looks like this:  
<source lang = "C">
<source lang = "C">
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F


00000000  00 02 00 00 00 00 00 00 05 00 00 00 03 00 00 00  ................ <<< Metadata header (0x20 long) ;  metasize (u64), signature type (u32) number of sections (u32) // Sig type 5 = RSA
00000000  00 02 00 00 00 00 00 00 05 00 00 00 03 00 00 00  ................ <<< Certification Header
00000010  0E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000010  0E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ <<< Certification Header
00000020  00 03 00 00 00 00 00 00 40 00 00 00 00 00 00 00  ........@.......
00000020  00 03 00 00 00 00 00 00 40 00 00 00 00 00 00 00  ........@.......
00000030  01 00 00 00 01 00 00 00 06 00 00 00 00 00 00 00  ................
00000030  01 00 00 00 01 00 00 00 06 00 00 00 00 00 00 00  ................
Line 380: Line 394:
00000170  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< Random key
00000170  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< Random key
00000180  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< Random IV
00000180  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< Random IV
00000190  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000190  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000001A0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
000001A0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000001B0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
000001B0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000001C0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
000001C0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000001D0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
000001D0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000001E0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
000001E0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000001F0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
000001F0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000200  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000200  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000210  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000210  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000220  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000220  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000230  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000230  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000240  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000240  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000250  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000250  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000260  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000260  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000270  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< RSA SIG
00000270  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
</source>
</source>


* Step 4: Get plain SELF sections
* Step 4: Decrypt CF segments if needed
 
CF segments can be encrypted. This is reported in the Segment Certification Header. Use the keys and IVs from the Attributes with the specified algorithm to decrypt the respective segments.
 
* Step 5: Uncompress CF segments if needed


Use the keys and IVs from the metadata to decrypt their respective sections using AES128-CTR.
CF segments can be compressed. This is reported in the Segment Certification Header.


* Step 5: Uncompress sections if needed


Sections can be compressed. This is reported in the header.
{{File Formats}}
<noinclude>[[Category:Main]]</noinclude>

Latest revision as of 22:35, 15 December 2024

Certified Files are the most common encrypted files on PS3 and PS Vita.

Introduction[edit | edit source]

Not only ELF/PRX files can be signed with this format, other known Certified Files are:

  • revoke list
  • PS3 security policy profile
  • system software package (.pkg)
  • system software package header (.spkg_hdr.X)
  • PS Vita diff file (never met such a file yet)
  • PS Vita game cartridge param.sfo (gro0:gc/param.sfo)
  • PS Vita launch list (SPKG with filename extension .dat)

Structure[edit | edit source]

It is important to notice that PS3 uses big-endian whilst PS Vita uses little-endian.

Header[edit | edit source]

typedef struct { // Size is 0x20 for v2, 0x30 for v3
	uint32_t magic;
	uint32_t version;
	uint16_t attribute;
	uint16_t category;
	uint32_t ext_header_size;
	uint64_t file_offset;
	uint64_t file_size;
	union {
		struct {
			uint64_t cf_file_size;
			uint64_t padding;
		};
	};
} __attribute__((packed)) cf_header;
field offset type notes
Magic 0x0 u32 Must be "SCE\0".
Version 0x4 u32 2 for PS3, 3 for PS Vita.
Attribute 0x8 u16 Corresponds to the revision of the encryption key. The Certified File Key ID is derived from the attribute.
Category 0xA u16 See Category.
Extended Header size 0xC u32 For SELF category only, set to 0 for other categories. See SELF_-_SPRX#Segment_Extended_Header.
File offset 0x10 u64 Offset to encapsulated data.
File size 0x18 u64 Size of the encapsulated data.
CF file size 0x20 u64 Size of the CF file. Present on version 3 only.
Padding 0x28 u64 Padding. Set to 0. Present on version 3 only.

Category[edit | edit source]

Value Type Name Remark
1 SELF - SPRX signed-elf - signed-prx Used for storing ELF and PRX. Both PS3 and PS Vita.
2 SRVK signed-revoke-list Used for Revokation. Both PS3 and PS Vita.
3 SPKG signed-package Used for System Software Packages. Both PS3 and PS Vita.
4 SSPP signed-security-policy-profile The only file of this category is Default.spp. PS3 only.
5 SDIFF signed-diff Used in Prototype PS Vita Applier module. PS Vita only. No sample file available.
6 SPSFO signed-param-sfo Spsfo (signed param.sfo) file is located in game cartridge at path gro0:gc/param.sfo. PS Vita only.

Encryption Root Header[edit | edit source]

Temporary name was Metadata Information. Official name is encryption_root_header.

Encryption Root Header is not present in fCF (fSELF, fSPP, etc...).

Encryption Root Header is decrypted using AES256CBC with the key and iv from System Software.

Struct[edit | edit source]

typedef struct {
	uint8_t key[16];
	uint8_t key_pad[16];
	uint8_t iv[16];
	uint8_t iv_pad[16];
} __attribute__((packed)) cf_encryption_root_header;

Comments[edit | edit source]

Certification Header[edit | edit source]

Temporary name was Metadata Header. Official name is certification_header.

Certification Header is only present if the Encryption Root Header is present. In that case, Certification Header is located after the Encryption Root Header.

Certification Header is decrypted using AES128 with the key and iv entries from the Encryption Root Header.

Struct[edit | edit source]

typedef struct {
	uint64_t sign_offset;
	uint32_t sign_algorithm;            // 1 = ECDSA160, 2 = HMACSHA1, 3 = SHA1, 5 = RSA2048, 6 = HMACSHA256 (?not used?)
	uint32_t cert_entry_num;
	uint32_t attr_entry_num;
	uint32_t optional_header_size;
	uint64_t pad;
} __attribute__((packed)) cf_certification_header;

Comments[edit | edit source]

Certification Body[edit | edit source]

Certification Body is located just after the Certification Header.

Certification Body is decrypted using AES128 with the key and iv entries from the Encryption Root Header.

Segment Certification Header[edit | edit source]

Temporary name was Metadata Section Header. Official name is segment_certification_header.

Segment Certification Header is only present if the Certification Header is present.

The number of Segment Certification Headers is indicated by the cert_entry_num field in the Certification Header.

Segment Certification Header is located after the Certification Header.

Struct[edit | edit source]

typedef struct {
	uint64_t segment_offset;
	uint64_t segment_size;
	uint32_t segment_type;      // 1 = shdr, 2 = phdr, 3 = sceversion
	uint32_t segment_id;        // 0,1,2,3,etc for phdr, always 3 for shdrs, sceversion shdr number for sceversion
	uint32_t sign_algorithm;    // 1 = ECDSA160 (not used), 2 = HMACSHA1, 3 = SHA1, 5 = RSA2048 (not used), 6 = HMACSHA256
	uint32_t sign_idx;
	uint32_t enc_algorithm;     // 1 = none, 2 = aes128cbccfb, 3 = aes128ctr
	uint32_t key_idx;           // -1 when enc_algorithm = none
	uint32_t iv_idx;            // -1 when enc_algorithm = none
	uint32_t comp_algorithm;    // 1 = plain, 2 = zlib
} __attribute__((packed)) cf_segment_certification_header;

Comments[edit | edit source]

  • Segment data is decrypted using enc_algorithm with the key and iv specified by key_idx and iv_idx, in the Attributes.
  • The segment_offset field in the Segment Certification Header usually matches the offset field in the Segment Extended Header.

Attributes[edit | edit source]

Temporary name was Metadata Keys, Section Hash, Segment Certification. Official name is attribute(s), found sub get_attribute(unsigned char *, unsigned int) on spp_verifier which returns pointer to signature/key/iv by its id.

The number of Attributes is indicated by the attr_entry_num field in the Certification Header.

Attributes are located after the Segment Certification Headers.

Struct[edit | edit source]

typedef struct {
	union { // size is 0x60 bytes
		uint8_t signature[0x20]; // hmac_sha1_hash
		uint8_t sign_key[0x40];
	} signature_type2;
	union { // size is 0x20 bytes
		uint8_t signature[0x20]; // sha1_hash
	} signature_type3;
	union { // size is 0x40 bytes
		uint8_t signature[0x20]; // hmac_sha256_hash
		uint8_t sign_key[0x20];
	} signature_type6;
	union { // size is 0x20 bytes
		uint8_t key[0x10];
		uint8_t iv[0x10];
	} encryption_params; // present for enc_algorithm type 2 and 3
} __attribute__((packed)) cf_attribute;

Comments[edit | edit source]

  • The signature is calculated on the decrypted data and before the decompression.

Optional Header Table[edit | edit source]

Temporary name was Signature Info, Capabilities Info. Official name is optional_header_table.

Optional Header Table is only present if optional_header_size in the Certification Header is not zero. In that case, Optional Header Table is located after the Attributes.

Struct[edit | edit source]

typedef struct {
	uint32_t type; // 1=capability_header, 2=individual_seed_header, 3=attribute_header
	uint32_t size;
	uint64_t next; // 1 if another cf_optional_header structure follows else 0
	union {
		// type 1
		struct { // 0x20 bytes of data
			uint8_t capability[0x20];
		} capability_header;
		// type 2
		struct { // 0x100 bytes of data
			uint8_t individual_seed[0x100];
		} individual_seed_header;
		// type 3
		struct { // 0x20 bytes of data
			uint8_t attribute[0x20];
		} attribute_header;
	};
} __attribute__((packed)) cf_optional_header;

Comments[edit | edit source]

  • Optional Header Type 1 contains encrypted_capability (not plaintext capability). See Capability Flags.

Signature[edit | edit source]

Official name might be Signature.

Signature is located at the Certification Header sign_offset in the Certified File.

Signature is decrypted with the key and iv entries from the Encryption Root Header.

Signature algorithm can be ECDSA160 or RSA2048, according to the Certification Header.

Struct[edit | edit source]

typedef struct {
	union {
		uint8_t r[21];
		uint8_t s[21];
		uint8_t padding[6];
	} ECDSA160;
	union {
		uint8_t rsa[0x100];
	} RSA2048;
} __attribute__((packed)) cf_signature;

Comments[edit | edit source]

  • sign_offset is the size of the data on which is computed the signature, from the start of the Certified File. The decrypted version of the input data is used for signature.

Decryption[edit | edit source]

Certified Files are all encrypted using the exact same algorithm (except for Fake Certified Files). They can be encrypted, hashed and signed. This section only focuses on the encryption layer.

  • Step 0: Get Encryption Root Header Master Keys

On PS3, TO DOCUMENT.

On PS Vita, static key and IV are contained within the relevant Secure Module. For example, SPKG keys are located in update_service_sm.self, KPRX keys are located in kprx_auth_sm.self, Security Modules keys and kernel_boot_loader.self keys are located in secure_kernel.

  • Step 1: Get Encryption Root Key and IV

Decrypt the Certification Header using AES256CBC on PS Vita (to document for PS3).

This results into the key and IV used in step 2.

  • Step 2: Get plain Certification

Use the key and IV decrypted from the Encryption Root Header to decrypt the Certification using AES128CBC on PS Vita (what on PS3?).

  • Step 3: Parse Certification

SELF Certification is typically stored in the following format. Below is an example of a 4-segments PS Vita SELF.

SPKG Certification follows the same principles but is slightly different (different Magic/Header).

Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000  F0 07 00 00 00 00 00 00 05 00 00 00 04 00 00 00  ð...............  <<< Certification Header
00000010  18 00 00 00 70 01 00 00 00 00 00 00 00 00 00 00  ....p...........  <<< Certification Header
00000020  00 0A 00 00 00 00 00 00 C0 00 00 00 00 00 00 00  ........À.......  <<< First segment address
00000030  02 00 00 00 01 00 00 00 06 00 00 00 00 00 00 00  ................
00000040  03 00 00 00 04 00 00 00 05 00 00 00 01 00 00 00  ................
00000050  00 0B 00 00 00 00 00 00 FC B4 07 00 00 00 00 00  ........ü´......  <<< Second segment address
00000060  02 00 00 00 02 00 00 00 06 00 00 00 06 00 00 00  ................
00000070  03 00 00 00 0A 00 00 00 0B 00 00 00 01 00 00 00  ................
00000080  00 C0 07 00 00 00 00 00 98 1E 00 00 00 00 00 00  .À......˜.......  <<< Third segment address
00000090  02 00 00 00 03 00 00 00 06 00 00 00 0C 00 00 00  ................
000000A0  03 00 00 00 10 00 00 00 11 00 00 00 01 00 00 00  ................
000000B0  00 DF 07 00 00 00 00 00 9D BA 02 00 00 00 00 00  .ß.......º......  <<< Fourth segment address
000000C0  02 00 00 00 04 00 00 00 06 00 00 00 12 00 00 00  ................
000000D0  03 00 00 00 16 00 00 00 17 00 00 00 01 00 00 00  ................
000000E0  AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªªªªªª  <<< First segment Hash
000000F0  AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªªªªªª  <<< First segment Hash
00000100  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
00000110  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
00000120  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< First segment random key
00000130  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< First segment random IV
00000140  BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB  »»»»»»»»»»»»»»»»  <<< Second segment Hash
00000150  BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB  »»»»»»»»»»»»»»»»  <<< Second segment Hash
00000160  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
00000170  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
00000180  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Second segment random key
00000190  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Second segment random IV
000001A0  CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC  ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ  <<< Third segment Hash
000001B0  CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC  ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ  <<< Third segment Hash
000001C0  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
000001D0  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
000001E0  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Third segment random key
000001F0  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Third segment random IV
00000200  DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD  ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ  <<< Fourth segment Hash
00000210  DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD  ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ  <<< Fourth segment Hash
00000220  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
00000230  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< HMAC key
00000240  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Fourth segment random key
00000250  EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE  îîîîîîîîîîîîîîîî  <<< Fourth segment random IV
00000260  01 00 00 00 30 00 00 00 01 00 00 00 00 00 00 00  ....0...........  <<< type (u32), segment size (u32), isMoreSegments (u32)
00000270  80 00 00 00 C0 00 F0 00 00 00 00 00 FF FF FF FF  ...À.ð.....ÿÿÿÿ 
00000270  80 00 00 00 C0 00 F0 00 00 00 00 00 FF FF FF FF  ...À.ð.....ÿÿÿÿ
00000280  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000290  02 00 00 00 10 01 00 00 01 00 00 00 00 00 00 00  ................  <<< type (u32), segment size (u32), isMoreSegments (u32)
000002A0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000002B0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000002C0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000002D0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000002E0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000002F0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000300  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000310  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000320  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000330  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000340  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000350  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000360  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000370  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000380  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000390  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
000003A0  03 00 00 00 30 00 00 00 00 00 00 00 00 00 00 00  ....0...........  <<< type (u32), segment size (u32), isMoreSegments (u32)
000003B0  80 09 80 03 00 00 C3 00 00 00 80 09 80 00 00 00  ....Ã.......
000003C0  00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF  ............ÿÿÿÿ
000003D0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000003E0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000003F0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000400  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000410  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000420  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000430  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000440  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000450  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000460  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000470  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000480  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000490  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000004A0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000004B0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000004C0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000004D0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................  <<< Certification Body end, padding

Following the same principles, a plain SPKG Certification Body looks like this:

Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000  00 02 00 00 00 00 00 00 05 00 00 00 03 00 00 00  ................ <<< Certification Header
00000010  0E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ <<< Certification Header
00000020  00 03 00 00 00 00 00 00 40 00 00 00 00 00 00 00  ........@.......
00000030  01 00 00 00 01 00 00 00 06 00 00 00 00 00 00 00  ................
00000040  01 00 00 00 FF FF FF FF FF FF FF FF 01 00 00 00  ....ÿÿÿÿÿÿÿÿ....
00000050  40 03 00 00 00 00 00 00 40 00 00 00 00 00 00 00  @.......@.......
00000060  02 00 00 00 02 00 00 00 06 00 00 00 04 00 00 00  ................
00000070  01 00 00 00 FF FF FF FF FF FF FF FF 01 00 00 00  ....ÿÿÿÿÿÿÿÿ....
00000080  80 03 00 00 00 00 00 00 00 00 80 00 00 00 00 00  ..............
00000090  03 00 00 00 03 00 00 00 06 00 00 00 08 00 00 00  ................
000000A0  03 00 00 00 0C 00 00 00 0D 00 00 00 01 00 00 00  ................
000000B0  AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªªªªªª  <<< Hash
000000C0  AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA  ªªªªªªªªªªªªªªªª  <<< Hash
000000D0  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
000000E0  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
000000F0  BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB  »»»»»»»»»»»»»»»»  <<< Hash
00000100  BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB  »»»»»»»»»»»»»»»»  <<< Hash
00000110  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
00000120  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
00000130  CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC  ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ  <<< Hash
00000140  CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC  ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ  <<< Hash
00000150  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< Random key
00000160  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< Random IV
00000170  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< Random key
00000180  FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  <<< Random IV
00000190  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000001A0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000001B0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000001C0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000001D0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000001E0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
000001F0  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000200  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000210  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000220  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000230  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000240  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000250  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000260  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
00000270  11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11  ................  <<< Signature (RSA2048)
  • Step 4: Decrypt CF segments if needed

CF segments can be encrypted. This is reported in the Segment Certification Header. Use the keys and IVs from the Attributes with the specified algorithm to decrypt the respective segments.

  • Step 5: Uncompress CF segments if needed

CF segments can be compressed. This is reported in the Segment Certification Header.