nx_x509_pubkey_rsa_4096.nx source
↩ module page · 117 lines · 3885 B
1// nx_x509_pubkey_rsa_4096.nx -- extract an RSA-4096 public key (n, e)
2// from an X.509 SubjectPublicKeyInfo. Parallel to
3// nx_x509_pubkey_rsa.nx (the 2048 variant).
4//
5// Same DER walk as the 2048 variant; only differences:
6// - mag_len cap is 512 (was 256)
7// - leading-0 sign byte case handles n_len == 513 (was 257)
8// - loads into a 128-limb u4096 buffer (was 64-limb u2048)
9//
10// Public API:
11// nx_x509_pubkey_extract_rsa_4096(buf, cert, out_n_4096, out_e_p) -> verdict
12//
13// Sealed verdict shape mirrors the 2048 variant.
14//
15// license_tier: INDEPENDENT_REDERIVE
16// genealogy_id: international-research-sources/ietf/rfc_8017 + rfc_5280
17// lineage_id: nishi_x509_pubkey_rsa_4096_q1
18
19import "nx_syscalls.nx"
20import "nx_asn1.nx"
21import "nx_u4096.nx"
22import "nx_x509.nx"
23
24const NX_X509_PUBKEY_RSA_4096_OK: i64 = 1
25const NX_X509_PUBKEY_RSA_4096_BAD_SEQUENCE: i64 = 2
26const NX_X509_PUBKEY_RSA_4096_BAD_N: i64 = 3
27const NX_X509_PUBKEY_RSA_4096_BAD_E: i64 = 4
28const NX_X509_PUBKEY_RSA_4096_VERDICT_N: i64 = 5
29
30func nx_x509_pubkey_rsa_4096_verdict_is_valid(v: i64) -> i64 {
31 if v < NX_X509_PUBKEY_RSA_4096_OK { return 0 }
32 if v >= NX_X509_PUBKEY_RSA_4096_VERDICT_N { return 0 }
33 return 1
34}
35
36func nx_x509_pubkey_extract_rsa_4096(buf: *u8, cert: *X509Cert,
37 out_n: *i64, out_e: *i64) -> i64 {
38 let pubkey_off: i64 = cert.pubkey_off
39 let pubkey_len: i64 = cert.pubkey_len
40
41 let c_raw: *u8 = sys_mmap(32)
42 let c: *Asn1Cursor = c_raw as *Asn1Cursor
43 c.pos = pubkey_off
44 c.end = pubkey_off + pubkey_len
45
46 // Outer SEQUENCE
47 let seq_len_p: *i64 = sys_mmap(16) as *i64
48 let rc1: i64 = asn1_expect_tag(buf, c, ASN1_SEQUENCE, seq_len_p)
49 if rc1 < 0 { return NX_X509_PUBKEY_RSA_4096_BAD_SEQUENCE }
50 let seq_end: i64 = c.pos + *seq_len_p
51 if seq_end > c.end { return NX_X509_PUBKEY_RSA_4096_BAD_SEQUENCE }
52
53 // n INTEGER
54 let n_len_p: *i64 = sys_mmap(16) as *i64
55 let rc2: i64 = asn1_expect_tag(buf, c, ASN1_INTEGER, n_len_p)
56 if rc2 < 0 { return NX_X509_PUBKEY_RSA_4096_BAD_N }
57 let n_off: i64 = c.pos
58 let n_len: i64 = *n_len_p
59 c.pos = c.pos + n_len
60 if c.pos > seq_end { return NX_X509_PUBKEY_RSA_4096_BAD_N }
61
62 // DER may include a leading 0x00 sign byte if MSB set.
63 // For 4096-bit modulus: n_len is 513 (with leading 0) or 512 (without).
64 var skip: i64 = 0
65 var mag_len: i64 = n_len
66 if n_len == 513 {
67 if (buf[n_off] & 0xff) != 0 { return NX_X509_PUBKEY_RSA_4096_BAD_N }
68 skip = 1
69 mag_len = 512
70 }
71 if mag_len > 512 { return NX_X509_PUBKEY_RSA_4096_BAD_N }
72 if mag_len < 1 { return NX_X509_PUBKEY_RSA_4096_BAD_N }
73
74 // Zero-pad up to 512 bytes BE then load as u4096.
75 let padded: *u8 = sys_mmap(512)
76 var i: i64 = 0
77 while i < 512 {
78 padded[i] = 0
79 i = i + 1
80 }
81 let pad_off: i64 = 512 - mag_len
82 i = 0
83 while i < mag_len {
84 padded[pad_off + i] = buf[n_off + skip + i]
85 i = i + 1
86 }
87 u4096_load_be(out_n, padded)
88
89 // e INTEGER (small; accept up to 8 bytes magnitude)
90 let e_len_p: *i64 = sys_mmap(16) as *i64
91 let rc3: i64 = asn1_expect_tag(buf, c, ASN1_INTEGER, e_len_p)
92 if rc3 < 0 { return NX_X509_PUBKEY_RSA_4096_BAD_E }
93 let e_off: i64 = c.pos
94 let e_len: i64 = *e_len_p
95 c.pos = c.pos + e_len
96 if c.pos > seq_end { return NX_X509_PUBKEY_RSA_4096_BAD_E }
97 if e_len < 1 { return NX_X509_PUBKEY_RSA_4096_BAD_E }
98 if e_len > 8 { return NX_X509_PUBKEY_RSA_4096_BAD_E }
99
100 var e_val: i64 = 0
101 var skip_e: i64 = 0
102 if (buf[e_off] & 0xff) == 0 {
103 if e_len > 1 { skip_e = 1 }
104 }
105 i = skip_e
106 while i < e_len {
107 e_val = (e_val << 8) | (buf[e_off + i] & 0xff)
108 i = i + 1
109 }
110 *out_e = e_val
111
112 return NX_X509_PUBKEY_RSA_4096_OK
113}
114
115func main() -> i64 {
116 return 0
117}