code wiki / (root) / nx_x509_pubkey_rsa.nx

nx_x509_pubkey_rsa.nx source

↩ module page · 131 lines · 4357 B

1// nx_x509_pubkey_rsa.nx -- extract an RSA-2048 public key (n, e) from 2// an X.509 SubjectPublicKeyInfo. 3// 4// Parallel to nx_x509_pubkey_ec.nx; reads the cert.pubkey_off/_len 5// bytes (the BIT STRING contents, with the unused-bits byte already 6// stripped by x509_parse). The contents are a DER-encoded 7// 8// RSAPublicKey ::= SEQUENCE { 9// modulus INTEGER, -- n (2048-bit unsigned) 10// publicExponent INTEGER -- e (typically 65537) 11// } 12// 13// Public API: 14// nx_x509_pubkey_extract_rsa(buf, cert, out_n_2048, out_e_p) -> verdict 15// 16// Writes: 17// out_n_2048: 64-limb LE U2048 modulus 18// *out_e_p: i64 public exponent 19// 20// Sealed verdict: 21// NX_X509_PUBKEY_RSA_OK 22// NX_X509_PUBKEY_RSA_BAD_SEQUENCE outer SEQUENCE missing/malformed 23// NX_X509_PUBKEY_RSA_BAD_N n INTEGER missing/out-of-range 24// NX_X509_PUBKEY_RSA_BAD_E e INTEGER missing/oversized 25// 26// Per Cardinals 9, 12, 23. 27// 28// license_tier: INDEPENDENT_REDERIVE 29// genealogy_id: international-research-sources/ietf/rfc_8017 + rfc_5280 30// lineage_id: nishi_x509_pubkey_rsa_q10 31 32// nx_safety_envelope: 33// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 34// sil_target: SIL1 35// evidence: [bulk_applied_2026-05-20, x509-rsa-pubkey-extract] 36// verdict: NOT_YET_EVALUATED 37 38import "nx_syscalls.nx" 39import "nx_asn1.nx" 40import "nx_u2048.nx" 41import "nx_x509.nx" 42 43const NX_X509_PUBKEY_RSA_OK: i64 = 1 44const NX_X509_PUBKEY_RSA_BAD_SEQUENCE: i64 = 2 45const NX_X509_PUBKEY_RSA_BAD_N: i64 = 3 46const NX_X509_PUBKEY_RSA_BAD_E: i64 = 4 47const NX_X509_PUBKEY_RSA_VERDICT_N: i64 = 5 48 49func nx_x509_pubkey_rsa_verdict_is_valid(v: i64) -> i64 { 50 if v < NX_X509_PUBKEY_RSA_OK { return 0 } 51 if v >= NX_X509_PUBKEY_RSA_VERDICT_N { return 0 } 52 return 1 53} 54 55// Extract RSA pubkey from cert's SPKI. 56func nx_x509_pubkey_extract_rsa(buf: *u8, cert: *X509Cert, 57 out_n: *i64, out_e: *i64) -> i64 { 58 let pubkey_off: i64 = cert.pubkey_off 59 let pubkey_len: i64 = cert.pubkey_len 60 61 let c_raw: *u8 = sys_mmap(32) 62 let c: *Asn1Cursor = c_raw as *Asn1Cursor 63 c.pos = pubkey_off 64 c.end = pubkey_off + pubkey_len 65 66 // Outer SEQUENCE 67 let seq_len_p: *i64 = sys_mmap(16) as *i64 68 let rc1: i64 = asn1_expect_tag(buf, c, ASN1_SEQUENCE, seq_len_p) 69 if rc1 < 0 { return NX_X509_PUBKEY_RSA_BAD_SEQUENCE } 70 let seq_end: i64 = c.pos + *seq_len_p 71 if seq_end > c.end { return NX_X509_PUBKEY_RSA_BAD_SEQUENCE } 72 73 // n INTEGER 74 let n_len_p: *i64 = sys_mmap(16) as *i64 75 let rc2: i64 = asn1_expect_tag(buf, c, ASN1_INTEGER, n_len_p) 76 if rc2 < 0 { return NX_X509_PUBKEY_RSA_BAD_N } 77 let n_off: i64 = c.pos 78 let n_len: i64 = *n_len_p 79 c.pos = c.pos + n_len 80 if c.pos > seq_end { return NX_X509_PUBKEY_RSA_BAD_N } 81 82 // DER may include a leading 0x00 sign byte if MSB set. 83 var skip: i64 = 0 84 var mag_len: i64 = n_len 85 if n_len == 257 { 86 if (buf[n_off] & 0xff) != 0 { return NX_X509_PUBKEY_RSA_BAD_N } 87 skip = 1 88 mag_len = 256 89 } 90 if mag_len > 256 { return NX_X509_PUBKEY_RSA_BAD_N } 91 if mag_len < 1 { return NX_X509_PUBKEY_RSA_BAD_N } 92 93 // Zero-pad up to 256 bytes BE then load as u2048. 94 let padded: *u8 = sys_mmap(256) 95 var i: i64 = 0 96 while i < 256 { padded[i] = 0; i = i + 1 } 97 let pad_off: i64 = 256 - mag_len 98 i = 0 99 while i < mag_len { 100 padded[pad_off + i] = buf[n_off + skip + i] 101 i = i + 1 102 } 103 u2048_load_be(out_n, padded) 104 105 // e INTEGER (small; we accept up to 8 bytes magnitude) 106 let e_len_p: *i64 = sys_mmap(16) as *i64 107 let rc3: i64 = asn1_expect_tag(buf, c, ASN1_INTEGER, e_len_p) 108 if rc3 < 0 { return NX_X509_PUBKEY_RSA_BAD_E } 109 let e_off: i64 = c.pos 110 let e_len: i64 = *e_len_p 111 c.pos = c.pos + e_len 112 if c.pos > seq_end { return NX_X509_PUBKEY_RSA_BAD_E } 113 if e_len < 1 { return NX_X509_PUBKEY_RSA_BAD_E } 114 if e_len > 8 { return NX_X509_PUBKEY_RSA_BAD_E } 115 116 var e_val: i64 = 0 117 var skip_e: i64 = 0 118 if (buf[e_off] & 0xff) == 0 && e_len > 1 { skip_e = 1 } 119 i = skip_e 120 while i < e_len { 121 e_val = (e_val << 8) | (buf[e_off + i] & 0xff) 122 i = i + 1 123 } 124 *out_e = e_val 125 126 return NX_X509_PUBKEY_RSA_OK 127} 128 129func main() -> i64 { 130 return 0 131}