code wiki / (root) / nx_lib_fetch_cookie.nx

nx_lib_fetch_cookie.nx source

↩ module page · 134 lines · 7557 B

1// nx_lib_fetch_cookie.nx -- sovereign HTTPS GET with a browser UA + Cookie 2// header, for sources gated behind a cookie (e.g. a solved proof-of-work). 3// Same TLS-1.3 connect+handshake as nx_lib_fetch; request builder + round-trip 4// modeled on nx_https_get_spoof's sp_build/sp_get_complete (which lives in a 5// main-bearing organ, so cannot be imported). license_tier: ORIGINAL 6import "nx_syscalls.nx" 7import "nx_csprng.nx" 8import "nx_x509_trust_store.nx" 9import "nx_tls13_client_session_run.nx" 10import "nx_tls13_client_session.nx" 11import "nx_tls13_record.nx" 12import "nx_tls13_read_record_from_fd.nx" 13import "nx_https_url_for_fetch.nx" 14import "nx_https_url_connect.nx" 15import "nx_https_get_complete.nx" 16const K_MAGIC_8192: i64 = 8192 17 18func lfc_puts(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[off+i] = s[i]; i = i + 1 } return off + i } 19 20func lfc_write_n(fd: i64, buf: *u8, n: i64) -> i64 { 21 var off: i64 = 0 22 while off < n { let w: i64 = sys_write(fd, (buf as i64 + off) as *u8, n - off); if w <= 0 { return 0 - 1 } off = off + w } 23 return 0 24} 25 26// browser-UA GET request with a Cookie header (identity encoding). 27func lfc_build(path: *u8, plen: i64, host: *u8, hlen: i64, cookie: *u8, clen: i64, out: *u8) -> i64 { 28 var o: i64 = 0 29 o = lfc_puts(out, o, "GET " as *u8) 30 var i: i64 = 0; while i < plen { out[o] = path[i]; o = o + 1; i = i + 1 } 31 o = lfc_puts(out, o, " HTTP/1.1\r\nHost: " as *u8) 32 i = 0; while i < hlen { out[o] = host[i]; o = o + 1; i = i + 1 } 33 o = lfc_puts(out, o, "\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:115.0) Gecko/20100101 Firefox/115.0\r\n" as *u8) 34 o = lfc_puts(out, o, "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" as *u8) 35 o = lfc_puts(out, o, "Accept-Language: en-US,en;q=0.5\r\nAccept-Encoding: identity\r\nUpgrade-Insecure-Requests: 1\r\n" as *u8) 36 if clen > 0 { o = lfc_puts(out, o, "Cookie: " as *u8); i = 0; while i < clen { out[o] = cookie[i]; o = o + 1; i = i + 1 } o = lfc_puts(out, o, "\r\n" as *u8) } 37 o = lfc_puts(out, o, "Connection: close\r\n\r\n" as *u8) 38 return o 39} 40 41// cookie-aware get_complete over an established TLS session (mirrors sp_get_complete). 42func lfc_get_complete(s: *Tls13ClientSession, fd: i64, path: *u8, path_len: i64, host: *u8, host_len: i64, cookie: *u8, clen: i64, out_buf: *u8, out_cap: i64) -> i64 { 43 if s.state != NX_TLS13_CSESSION_STATE_CONNECTED { return 0 - NX_HTTPS_GC_BAD_STATE } 44 let req: *u8 = sys_mmap(K_MAGIC_8192) 45 let req_len: i64 = lfc_build(path, path_len, host, host_len, cookie, clen, req) 46 if req_len <= 0 { return 0 - NX_HTTPS_GC_BUILD_FAIL } 47 let rec_buf: *u8 = sys_mmap(req_len + 64) 48 let header_out: *u8 = rec_buf 49 let ct_out: *u8 = rec_buf + NX_TLS13_RECORD_HEADER_LEN 50 let tag_out: *u8 = rec_buf + NX_TLS13_RECORD_HEADER_LEN + req_len + 1 51 let enc_v: i64 = nx_tls13_record_encrypt_v2(s.cipher_suite, s.client_app_traffic_key, s.client_app_iv, s.client_app_seq, req, req_len, NX_TLS13_CT_APPLICATION_DATA, 0, header_out, ct_out, tag_out) 52 s.client_app_seq = s.client_app_seq + 1 53 if enc_v != NX_TLS13_REC_VERDICT_OK { return 0 - NX_HTTPS_GC_ENCRYPT_FAIL } 54 let total_rec_len: i64 = NX_TLS13_RECORD_HEADER_LEN + req_len + 1 + NX_TLS13_RECORD_TAG_LEN 55 if lfc_write_n(fd, rec_buf, total_rec_len) < 0 { return 0 - NX_HTTPS_GC_WRITE_FAIL } 56 var accumulated: i64 = 0 57 while accumulated < out_cap { 58 let rec_in: *u8 = sys_mmap(NX_HTTPS_GC_RESP_RECORD_BYTES) 59 let rec_in_total: i64 = nx_tls13_read_record_from_fd(fd, rec_in, NX_HTTPS_GC_RESP_RECORD_BYTES) 60 if rec_in_total < 0 { 61 let nv: i64 = 0 - rec_in_total 62 if nv == NX_TLS13_READ_REC_EOF { return accumulated } 63 if nv == NX_TLS13_READ_REC_PAYLOAD_EOF { return accumulated } 64 return 0 - NX_HTTPS_GC_READ_FAIL 65 } 66 let rec_in_header: *u8 = rec_in 67 let rec_in_ct: *u8 = rec_in + NX_TLS13_RECORD_HEADER_LEN 68 let rec_in_ct_len: i64 = rec_in_total - NX_TLS13_RECORD_HEADER_LEN - NX_TLS13_RECORD_TAG_LEN 69 let rec_in_tag: *u8 = rec_in + rec_in_total - NX_TLS13_RECORD_TAG_LEN 70 let plaintext: *u8 = sys_mmap(rec_in_ct_len + 16) 71 let pct: *i64 = sys_mmap(16) as *i64 72 let plen2: *i64 = sys_mmap(16) as *i64 73 let dec_v: i64 = nx_tls13_record_decrypt_v2(s.cipher_suite, s.server_app_traffic_key, s.server_app_iv, s.server_app_seq, rec_in_header, rec_in_ct, rec_in_ct_len, rec_in_tag, plaintext, pct, plen2) 74 s.server_app_seq = s.server_app_seq + 1 75 if dec_v != NX_TLS13_REC_VERDICT_OK { return 0 - NX_HTTPS_GC_DECRYPT_FAIL } 76 if pct[0] == NX_TLS13_CT_ALERT { return accumulated } 77 if pct[0] == NX_TLS13_CT_APPLICATION_DATA { 78 let avail: i64 = out_cap - accumulated 79 let to_copy: i64 = plen2[0] 80 if to_copy > avail { return 0 - NX_HTTPS_GC_BUF_OVERFLOW } 81 var i: i64 = 0; while i < to_copy { out_buf[accumulated+i] = plaintext[i]; i = i + 1 } 82 accumulated = accumulated + to_copy 83 } 84 } 85 return accumulated 86} 87 88// full cookie'd fetch: DNS+TCP connect -> TLS-1.3 handshake -> GET w/ cookie. 89func nx_lib_fetch_cookie(store: *TrustStore, url_str: *u8, cookie: *u8, clen: i64, out_buf: *u8, out_cap: i64) -> i64 { 90 let cr: *u8 = sys_mmap(32) 91 var i: i64 = 0 92 nx_csprng_fill(cr, 32) // CWE-330 (debt 1785970852): was the constant 0xC0..0xDF 93 let priv: *u8 = sys_mmap(32) 94 i = 0 95 nx_csprng_fill(priv, 32) // CWE-330: the X25519 scalar was the constant 0xA0..0xBF on EVERY session 96 let url_p: *NxUrl = nx_url_new() 97 let target_raw: *u8 = sys_mmap(32) 98 let target: *NxHttpsTarget = target_raw as *NxHttpsTarget 99 target.url = url_p 100 target.port = 0 101 if nx_https_url_for_fetch(url_str, target) != NX_HTTPS_URL_OK { return 0 - 41 } 102 let fd_p: *i64 = sys_mmap(16) as *i64 103 if nx_https_url_connect(target, url_str, sys_now_realtime_sec(), fd_p) != NX_HTTPS_CONNECT_OK { return 0 - 42 } 104 let fd: i64 = *fd_p 105 let val_ctx_raw: *u8 = sys_mmap(64) 106 let val_ctx: *TlsValidationContext = val_ctx_raw as *TlsValidationContext 107 val_ctx.store = store 108 val_ctx.sni_host = url_str + target.url.host_off 109 val_ctx.sni_host_len = target.url.host_len 110 val_ctx.now_epoch = sys_now_realtime_sec() 111 let sr: i64 = nx_tls13_client_session_run(fd, url_str + target.url.host_off, target.url.host_len, cr, priv, val_ctx) 112 if sr <= 0 { sys_close(fd); return 0 - (200 + (0 - sr)) } 113 let session: *Tls13ClientSession = sr as *Tls13ClientSession 114 var path_off: i64 = target.url.path_off 115 var path_len: i64 = target.url.path_len 116 let default_path: *u8 = sys_mmap(2) 117 default_path[0] = 0x2F as u8 118 var path_ptr: *u8 = url_str + path_off 119 if path_len == 0 { path_ptr = default_path; path_len = 1 } 120 if target.url.query_len > 0 { 121 let full: *u8 = sys_mmap(path_len + target.url.query_len + 4) 122 var fo: i64 = 0 123 var pci: i64 = 0 124 while pci < path_len { full[fo] = path_ptr[pci]; fo = fo + 1; pci = pci + 1 } 125 full[fo] = 0x3F as u8; fo = fo + 1 126 let qp: *u8 = url_str + target.url.query_off 127 var qci: i64 = 0 128 while qci < target.url.query_len { full[fo] = qp[qci]; fo = fo + 1; qci = qci + 1 } 129 path_ptr = full; path_len = fo 130 } 131 let n: i64 = lfc_get_complete(session, fd, path_ptr, path_len, url_str + target.url.host_off, target.url.host_len, cookie, clen, out_buf, out_cap) 132 sys_close(fd) 133 return n 134}