@gjsify/tls-native 0.4.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/_virtual/_rolldown/runtime.js +1 -0
- package/lib/esm/index.gjs.spec.js +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/types/index.d.ts +85 -0
- package/lib/types/index.gjs.spec.d.ts +2 -0
- package/meson.build +36 -0
- package/package.json +62 -0
- package/prebuilds/linux-x86_64/GjsifyTls-1.0.gir +153 -0
- package/prebuilds/linux-x86_64/GjsifyTls-1.0.typelib +0 -0
- package/prebuilds/linux-x86_64/libgjsifytls.so +0 -0
- package/src/vala/gnutls-ocsp.vapi +44 -0
- package/src/vala/tls.vala +159 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=Object.defineProperty,__name=(t,n)=>e(t,`name`,{value:n,configurable:!0});export{__name};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{__name as e}from"./_virtual/_rolldown/runtime.js";import{OcspCertStatus as t,OcspResponseStatus as n,hasNativeTls as r,nativeTls as i,parseOcspResponse as a}from"./index.js";import{describe as o,expect as s,it as c,on as l}from"@gjsify/unit";var u=e(async()=>{await l(`Gjs`,async()=>{await o(`@gjsify/tls-native — module loading`,async()=>{await c(`loads the GjsifyTls typelib successfully`,()=>{s(r()).toBe(!0),s(i).not.toBeNull(),s(typeof i?.Tls.parse_ocsp_response).toBe(`function`)})}),await o(`@gjsify/tls-native — parse_ocsp_response`,async()=>{await c(`returns null for empty input`,()=>{s(a(new Uint8Array)).toBeNull()}),await c(`returns null for non-OCSP garbage bytes`,()=>{s(a(new Uint8Array([255,255,255,255,1,2,3]))).toBeNull()}),await c(`returns null for truncated DER (sequence header only)`,()=>{s(a(new Uint8Array([48,1,0]))).toBeNull()})}),await o(`@gjsify/tls-native — symbolic constants`,async()=>{await c(`exposes OcspCertStatus enum-style constants`,()=>{s(t.GOOD).toBe(0),s(t.REVOKED).toBe(1),s(t.UNKNOWN).toBe(2)}),await c(`exposes OcspResponseStatus enum-style constants`,()=>{s(n.SUCCESSFUL).toBe(0),s(n.MALFORMED_REQUEST).toBe(1),s(n.INTERNAL_ERROR).toBe(2),s(n.TRY_LATER).toBe(3),s(n.SIG_REQUIRED).toBe(5),s(n.UNAUTHORIZED).toBe(6)})})})},`default`);export{u as default};
|
package/lib/esm/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";let e=null;const t=globalThis.imports?.gi;if(t)try{e=t.GjsifyTls}catch{}const n=e;function hasNativeTls(){return e!==null}function parseOcspResponse(t){if(!e)throw Error(`@gjsify/tls-native: native typelib not loaded. Check hasNativeTls() first.`);return e.Tls.parse_ocsp_response(t)}const r={GOOD:0,REVOKED:1,UNKNOWN:2},i={SUCCESSFUL:0,MALFORMED_REQUEST:1,INTERNAL_ERROR:2,TRY_LATER:3,SIG_REQUIRED:5,UNAUTHORIZED:6};export{r as OcspCertStatus,i as OcspResponseStatus,hasNativeTls,n as nativeTls,parseOcspResponse};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** Parsed OCSP response from `Tls.parse_ocsp_response`. Mirrors the
|
|
2
|
+
* GObject properties exposed by `GjsifyTls.OcspResponseInfo`. */
|
|
3
|
+
export interface OcspResponseInfo {
|
|
4
|
+
/**
|
|
5
|
+
* `responseStatus` per RFC 6960 §4.2.1.
|
|
6
|
+
* 0 = successful
|
|
7
|
+
* 1 = malformedRequest
|
|
8
|
+
* 2 = internalError
|
|
9
|
+
* 3 = tryLater
|
|
10
|
+
* 5 = sigRequired
|
|
11
|
+
* 6 = unauthorized
|
|
12
|
+
*/
|
|
13
|
+
responseStatus: number;
|
|
14
|
+
/** `producedAt` (Unix seconds, 0 if unparseable). */
|
|
15
|
+
producedAt: number;
|
|
16
|
+
/**
|
|
17
|
+
* `certStatus` per RFC 6960 §4.2.1.
|
|
18
|
+
* 0 = good
|
|
19
|
+
* 1 = revoked
|
|
20
|
+
* 2 = unknown
|
|
21
|
+
*/
|
|
22
|
+
certStatus: number;
|
|
23
|
+
/** `thisUpdate` (Unix seconds). */
|
|
24
|
+
thisUpdate: number;
|
|
25
|
+
/** `nextUpdate` (Unix seconds, 0 if absent). */
|
|
26
|
+
nextUpdate: number;
|
|
27
|
+
/** `revocationTime` (Unix seconds, only meaningful when certStatus=1). */
|
|
28
|
+
revocationTime: number;
|
|
29
|
+
/** `revocationReason` per RFC 5280 §5.3.1 CRL reason codes; meaningful
|
|
30
|
+
* only when certStatus=1. */
|
|
31
|
+
revocationReason: number;
|
|
32
|
+
}
|
|
33
|
+
/** Native handle returned by `imports.gi.GjsifyTls`. The shape mirrors
|
|
34
|
+
* the GIR — `OcspResponseInfo` properties are exposed in camelCase via
|
|
35
|
+
* GObject's automatic property accessor lowering on the GJS side. */
|
|
36
|
+
export interface NativeTls {
|
|
37
|
+
/**
|
|
38
|
+
* Parse a DER-encoded OCSP response (RFC 6960). Returns `null` when
|
|
39
|
+
* the bytes are not a valid response (init / import errors).
|
|
40
|
+
*/
|
|
41
|
+
parse_ocsp_response(bytes: Uint8Array): OcspResponseInfo | null;
|
|
42
|
+
}
|
|
43
|
+
export interface GjsifyTlsModule {
|
|
44
|
+
Tls: NativeTls;
|
|
45
|
+
}
|
|
46
|
+
/** The native GjsifyTls module, or `null` if not installed. */
|
|
47
|
+
export declare const nativeTls: GjsifyTlsModule | null;
|
|
48
|
+
/** Returns `true` when the GjsifyTls native library is available. */
|
|
49
|
+
export declare function hasNativeTls(): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Parse a DER-encoded OCSP response (RFC 6960).
|
|
52
|
+
*
|
|
53
|
+
* Throws when `@gjsify/tls-native`'s typelib is not loaded — callers can
|
|
54
|
+
* gate with `hasNativeTls()` and fall back to a pure-JS path (no such path
|
|
55
|
+
* exists today; OCSP parsing requires either the GnuTLS bridge here or a
|
|
56
|
+
* full RFC 6960 ASN.1 decoder).
|
|
57
|
+
*
|
|
58
|
+
* @param bytes DER-encoded OCSPResponse bytes (typically the body of a
|
|
59
|
+
* POST response from the cert's AIA OCSP responder URL).
|
|
60
|
+
* @returns Parsed response on success, `null` when the bytes don't
|
|
61
|
+
* parse as an OCSPResponse.
|
|
62
|
+
*/
|
|
63
|
+
export declare function parseOcspResponse(bytes: Uint8Array): OcspResponseInfo | null;
|
|
64
|
+
/**
|
|
65
|
+
* Symbolic OCSP cert-status values per RFC 6960 §4.2.1. Use as
|
|
66
|
+
* `OcspCertStatus.GOOD` for readable comparisons.
|
|
67
|
+
*/
|
|
68
|
+
export declare const OcspCertStatus: {
|
|
69
|
+
readonly GOOD: 0;
|
|
70
|
+
readonly REVOKED: 1;
|
|
71
|
+
readonly UNKNOWN: 2;
|
|
72
|
+
};
|
|
73
|
+
export type OcspCertStatus = (typeof OcspCertStatus)[keyof typeof OcspCertStatus];
|
|
74
|
+
/**
|
|
75
|
+
* Symbolic OCSP responseStatus values per RFC 6960 §4.2.1.
|
|
76
|
+
*/
|
|
77
|
+
export declare const OcspResponseStatus: {
|
|
78
|
+
readonly SUCCESSFUL: 0;
|
|
79
|
+
readonly MALFORMED_REQUEST: 1;
|
|
80
|
+
readonly INTERNAL_ERROR: 2;
|
|
81
|
+
readonly TRY_LATER: 3;
|
|
82
|
+
readonly SIG_REQUIRED: 5;
|
|
83
|
+
readonly UNAUTHORIZED: 6;
|
|
84
|
+
};
|
|
85
|
+
export type OcspResponseStatus = (typeof OcspResponseStatus)[keyof typeof OcspResponseStatus];
|
package/meson.build
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
project('GjsifyTls', ['c', 'vala'], version: '1.0')
|
|
2
|
+
|
|
3
|
+
root_dir = meson.current_source_dir()
|
|
4
|
+
|
|
5
|
+
dependencies = [
|
|
6
|
+
dependency('glib-2.0'),
|
|
7
|
+
dependency('gobject-2.0'),
|
|
8
|
+
dependency('gnutls'),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
sources = files(
|
|
12
|
+
'src/vala/tls.vala',
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
libGjsifyTls = library('gjsifytls', sources,
|
|
16
|
+
dependencies: dependencies,
|
|
17
|
+
vala_args: ['--pkg=gnutls', '--vapidir=' + meson.current_source_dir() / 'src/vala', '--pkg=gnutls-ocsp'],
|
|
18
|
+
vala_gir: meson.project_name() + '-1.0.gir',
|
|
19
|
+
install: true,
|
|
20
|
+
install_dir: [true, true, true, true],
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
g_ir_compiler = find_program('g-ir-compiler')
|
|
24
|
+
|
|
25
|
+
custom_target(meson.project_name() + '-1.0.typelib',
|
|
26
|
+
command: [
|
|
27
|
+
g_ir_compiler,
|
|
28
|
+
'--shared-library', 'libgjsifytls.so',
|
|
29
|
+
'--output', '@OUTPUT@',
|
|
30
|
+
meson.current_build_dir() / meson.project_name() + '-1.0.gir',
|
|
31
|
+
],
|
|
32
|
+
output: meson.project_name() + '-1.0.typelib',
|
|
33
|
+
depends: libGjsifyTls,
|
|
34
|
+
install: true,
|
|
35
|
+
install_dir: get_option('libdir') / 'girepository-1.0',
|
|
36
|
+
)
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gjsify/tls-native",
|
|
3
|
+
"version": "0.4.20",
|
|
4
|
+
"description": "Optional Vala/GObject bridge providing GnuTLS capabilities not exposed by Gio.TlsConnection — OCSP-response parsing (RFC 6960), session resumption data extraction, channel binding (tls-finished bytes for SCRAM-SHA-*). Enhances @gjsify/tls when installed.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/esm/index.js",
|
|
7
|
+
"module": "lib/esm/index.js",
|
|
8
|
+
"types": "lib/types/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./lib/types/index.d.ts",
|
|
12
|
+
"default": "./lib/esm/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"lib",
|
|
17
|
+
"prebuilds",
|
|
18
|
+
"meson.build",
|
|
19
|
+
"src/vala"
|
|
20
|
+
],
|
|
21
|
+
"gjsify": {
|
|
22
|
+
"prebuilds": "prebuilds"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"gjs",
|
|
26
|
+
"tls",
|
|
27
|
+
"gnutls",
|
|
28
|
+
"ocsp",
|
|
29
|
+
"ocsp-stapling",
|
|
30
|
+
"channel-binding",
|
|
31
|
+
"scram",
|
|
32
|
+
"session-resumption",
|
|
33
|
+
"vala",
|
|
34
|
+
"native"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"clear": "rm -rf lib build tsconfig.tsbuildinfo tsconfig.types.tsbuildinfo test.gjs.mjs || exit 0",
|
|
38
|
+
"check": "tsc --noEmit",
|
|
39
|
+
"build": "gjsify run build:gjsify && gjsify run build:types",
|
|
40
|
+
"build:gjsify": "gjsify build --library 'src/ts/**/*.{ts,js}'",
|
|
41
|
+
"build:types": "tsc",
|
|
42
|
+
"build:test:gjs": "gjsify build src/ts/test.mts --app gjs --outfile test.gjs.mjs",
|
|
43
|
+
"test": "gjsify run build:gjsify && gjsify run build:test:gjs && gjsify run test:gjs",
|
|
44
|
+
"test:gjs": "gjsify run test.gjs.mjs",
|
|
45
|
+
"init:meson": "meson setup build .",
|
|
46
|
+
"init:meson:wipe": "gjsify run init:meson --wipe",
|
|
47
|
+
"build:meson": "gjsify run init:meson && meson compile -C build",
|
|
48
|
+
"build:prebuilds": "gjsify run build:meson && mkdir -p prebuilds/linux-x86_64 && cp build/libgjsifytls.so build/GjsifyTls-1.0.gir build/GjsifyTls-1.0.typelib prebuilds/linux-x86_64/",
|
|
49
|
+
"build:gir-types": "ts-for-gir generate --externalDeps --allowMissingDeps --girDirectories=./prebuilds/linux-x86_64 --girDirectories=/usr/share/gir-1.0 --modules=GjsifyTls-1.0 --outdir=src/ts --npmScope=@girs --package=false --ignoreVersionConflicts=true"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@girs/glib-2.0": "2.88.0-4.0.0-rc.15",
|
|
53
|
+
"@girs/gobject-2.0": "2.88.0-4.0.0-rc.15"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@gjsify/cli": "workspace:^",
|
|
57
|
+
"@gjsify/unit": "workspace:^",
|
|
58
|
+
"@ts-for-gir/cli": "^4.0.0-rc.15",
|
|
59
|
+
"@types/node": "^25.6.2",
|
|
60
|
+
"typescript": "^6.0.3"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<?xml version="1.0"?>
|
|
2
|
+
<!-- GjsifyTls-1.0.gir generated by valac 0.56.18, do not modify. -->
|
|
3
|
+
<repository version="1.2" xmlns="http://www.gtk.org/introspection/core/1.0" xmlns:c="http://www.gtk.org/introspection/c/1.0" xmlns:glib="http://www.gtk.org/introspection/glib/1.0">
|
|
4
|
+
<include name="GObject" version="2.0"/>
|
|
5
|
+
<package name="gjsifytls"/>
|
|
6
|
+
<c:include name="gjsifytls.h"/>
|
|
7
|
+
<namespace name="GjsifyTls" version="1.0" c:prefix="GjsifyTls" c:identifier-prefixes="GjsifyTls" c:symbol-prefixes="gjsify_tls">
|
|
8
|
+
<class name="OcspResponseInfo" c:type="GjsifyTlsOcspResponseInfo" c:symbol-prefix="ocsp_response_info" glib:type-name="GjsifyTlsOcspResponseInfo" glib:get-type="gjsify_tls_ocsp_response_info_get_type" glib:type-struct="OcspResponseInfoClass" parent="GObject.Object">
|
|
9
|
+
<field name="parent_instance" readable="0" private="1">
|
|
10
|
+
<type name="GObject.Object" c:type="GObject"/>
|
|
11
|
+
</field>
|
|
12
|
+
<field name="priv" readable="0" private="1">
|
|
13
|
+
<type name="OcspResponseInfoPrivate" c:type="GjsifyTlsOcspResponseInfoPrivate*"/>
|
|
14
|
+
</field>
|
|
15
|
+
<constructor name="new" c:identifier="gjsify_tls_ocsp_response_info_new">
|
|
16
|
+
<return-value transfer-ownership="full">
|
|
17
|
+
<type name="GjsifyTls.OcspResponseInfo" c:type="GjsifyTlsOcspResponseInfo*"/>
|
|
18
|
+
</return-value>
|
|
19
|
+
</constructor>
|
|
20
|
+
<property name="response-status" writable="1">
|
|
21
|
+
<type name="gint" c:type="gint"/>
|
|
22
|
+
</property>
|
|
23
|
+
<method name="get_response_status" c:identifier="gjsify_tls_ocsp_response_info_get_response_status">
|
|
24
|
+
<return-value transfer-ownership="none">
|
|
25
|
+
<type name="gint" c:type="gint"/>
|
|
26
|
+
</return-value>
|
|
27
|
+
<parameters>
|
|
28
|
+
<instance-parameter name="self" transfer-ownership="none">
|
|
29
|
+
<type name="GjsifyTls.OcspResponseInfo" c:type="GjsifyTlsOcspResponseInfo*"/>
|
|
30
|
+
</instance-parameter>
|
|
31
|
+
</parameters>
|
|
32
|
+
</method>
|
|
33
|
+
<property name="produced-at" writable="1">
|
|
34
|
+
<type name="gint64" c:type="gint64"/>
|
|
35
|
+
</property>
|
|
36
|
+
<method name="get_produced_at" c:identifier="gjsify_tls_ocsp_response_info_get_produced_at">
|
|
37
|
+
<return-value transfer-ownership="none">
|
|
38
|
+
<type name="gint64" c:type="gint64"/>
|
|
39
|
+
</return-value>
|
|
40
|
+
<parameters>
|
|
41
|
+
<instance-parameter name="self" transfer-ownership="none">
|
|
42
|
+
<type name="GjsifyTls.OcspResponseInfo" c:type="GjsifyTlsOcspResponseInfo*"/>
|
|
43
|
+
</instance-parameter>
|
|
44
|
+
</parameters>
|
|
45
|
+
</method>
|
|
46
|
+
<property name="cert-status" writable="1">
|
|
47
|
+
<type name="gint" c:type="gint"/>
|
|
48
|
+
</property>
|
|
49
|
+
<method name="get_cert_status" c:identifier="gjsify_tls_ocsp_response_info_get_cert_status">
|
|
50
|
+
<return-value transfer-ownership="none">
|
|
51
|
+
<type name="gint" c:type="gint"/>
|
|
52
|
+
</return-value>
|
|
53
|
+
<parameters>
|
|
54
|
+
<instance-parameter name="self" transfer-ownership="none">
|
|
55
|
+
<type name="GjsifyTls.OcspResponseInfo" c:type="GjsifyTlsOcspResponseInfo*"/>
|
|
56
|
+
</instance-parameter>
|
|
57
|
+
</parameters>
|
|
58
|
+
</method>
|
|
59
|
+
<property name="this-update" writable="1">
|
|
60
|
+
<type name="gint64" c:type="gint64"/>
|
|
61
|
+
</property>
|
|
62
|
+
<method name="get_this_update" c:identifier="gjsify_tls_ocsp_response_info_get_this_update">
|
|
63
|
+
<return-value transfer-ownership="none">
|
|
64
|
+
<type name="gint64" c:type="gint64"/>
|
|
65
|
+
</return-value>
|
|
66
|
+
<parameters>
|
|
67
|
+
<instance-parameter name="self" transfer-ownership="none">
|
|
68
|
+
<type name="GjsifyTls.OcspResponseInfo" c:type="GjsifyTlsOcspResponseInfo*"/>
|
|
69
|
+
</instance-parameter>
|
|
70
|
+
</parameters>
|
|
71
|
+
</method>
|
|
72
|
+
<property name="next-update" writable="1">
|
|
73
|
+
<type name="gint64" c:type="gint64"/>
|
|
74
|
+
</property>
|
|
75
|
+
<method name="get_next_update" c:identifier="gjsify_tls_ocsp_response_info_get_next_update">
|
|
76
|
+
<return-value transfer-ownership="none">
|
|
77
|
+
<type name="gint64" c:type="gint64"/>
|
|
78
|
+
</return-value>
|
|
79
|
+
<parameters>
|
|
80
|
+
<instance-parameter name="self" transfer-ownership="none">
|
|
81
|
+
<type name="GjsifyTls.OcspResponseInfo" c:type="GjsifyTlsOcspResponseInfo*"/>
|
|
82
|
+
</instance-parameter>
|
|
83
|
+
</parameters>
|
|
84
|
+
</method>
|
|
85
|
+
<property name="revocation-time" writable="1">
|
|
86
|
+
<type name="gint64" c:type="gint64"/>
|
|
87
|
+
</property>
|
|
88
|
+
<method name="get_revocation_time" c:identifier="gjsify_tls_ocsp_response_info_get_revocation_time">
|
|
89
|
+
<return-value transfer-ownership="none">
|
|
90
|
+
<type name="gint64" c:type="gint64"/>
|
|
91
|
+
</return-value>
|
|
92
|
+
<parameters>
|
|
93
|
+
<instance-parameter name="self" transfer-ownership="none">
|
|
94
|
+
<type name="GjsifyTls.OcspResponseInfo" c:type="GjsifyTlsOcspResponseInfo*"/>
|
|
95
|
+
</instance-parameter>
|
|
96
|
+
</parameters>
|
|
97
|
+
</method>
|
|
98
|
+
<property name="revocation-reason" writable="1">
|
|
99
|
+
<type name="gint" c:type="gint"/>
|
|
100
|
+
</property>
|
|
101
|
+
<method name="get_revocation_reason" c:identifier="gjsify_tls_ocsp_response_info_get_revocation_reason">
|
|
102
|
+
<return-value transfer-ownership="none">
|
|
103
|
+
<type name="gint" c:type="gint"/>
|
|
104
|
+
</return-value>
|
|
105
|
+
<parameters>
|
|
106
|
+
<instance-parameter name="self" transfer-ownership="none">
|
|
107
|
+
<type name="GjsifyTls.OcspResponseInfo" c:type="GjsifyTlsOcspResponseInfo*"/>
|
|
108
|
+
</instance-parameter>
|
|
109
|
+
</parameters>
|
|
110
|
+
</method>
|
|
111
|
+
</class>
|
|
112
|
+
<record name="OcspResponseInfoClass" c:type="GjsifyTlsOcspResponseInfoClass" glib:is-gtype-struct-for="OcspResponseInfo">
|
|
113
|
+
<field name="parent_class" readable="0" private="1">
|
|
114
|
+
<type name="GObject.ObjectClass" c:type="GObjectClass"/>
|
|
115
|
+
</field>
|
|
116
|
+
</record>
|
|
117
|
+
<record name="OcspResponseInfoPrivate" c:type="GjsifyTlsOcspResponseInfoPrivate" disguised="1"/>
|
|
118
|
+
<class name="Tls" c:type="GjsifyTlsTls" c:symbol-prefix="tls" glib:type-name="GjsifyTlsTls" glib:get-type="gjsify_tls_tls_get_type" glib:type-struct="TlsClass" parent="GObject.Object">
|
|
119
|
+
<field name="parent_instance" readable="0" private="1">
|
|
120
|
+
<type name="GObject.Object" c:type="GObject"/>
|
|
121
|
+
</field>
|
|
122
|
+
<field name="priv" readable="0" private="1">
|
|
123
|
+
<type name="TlsPrivate" c:type="GjsifyTlsTlsPrivate*"/>
|
|
124
|
+
</field>
|
|
125
|
+
<function name="parse_ocsp_response" c:identifier="gjsify_tls_tls_parse_ocsp_response">
|
|
126
|
+
<return-value transfer-ownership="full" nullable="1">
|
|
127
|
+
<type name="GjsifyTls.OcspResponseInfo" c:type="GjsifyTlsOcspResponseInfo*"/>
|
|
128
|
+
</return-value>
|
|
129
|
+
<parameters>
|
|
130
|
+
<parameter name="bytes" transfer-ownership="none">
|
|
131
|
+
<array length="1" c:type="guint8*">
|
|
132
|
+
<type name="guint8" c:type="guint8"/>
|
|
133
|
+
</array>
|
|
134
|
+
</parameter>
|
|
135
|
+
<parameter name="bytes_length1" transfer-ownership="none">
|
|
136
|
+
<type name="gint" c:type="gint"/>
|
|
137
|
+
</parameter>
|
|
138
|
+
</parameters>
|
|
139
|
+
</function>
|
|
140
|
+
<constructor name="new" c:identifier="gjsify_tls_tls_new">
|
|
141
|
+
<return-value transfer-ownership="full">
|
|
142
|
+
<type name="GjsifyTls.Tls" c:type="GjsifyTlsTls*"/>
|
|
143
|
+
</return-value>
|
|
144
|
+
</constructor>
|
|
145
|
+
</class>
|
|
146
|
+
<record name="TlsClass" c:type="GjsifyTlsTlsClass" glib:is-gtype-struct-for="Tls">
|
|
147
|
+
<field name="parent_class" readable="0" private="1">
|
|
148
|
+
<type name="GObject.ObjectClass" c:type="GObjectClass"/>
|
|
149
|
+
</field>
|
|
150
|
+
</record>
|
|
151
|
+
<record name="TlsPrivate" c:type="GjsifyTlsTlsPrivate" disguised="1"/>
|
|
152
|
+
</namespace>
|
|
153
|
+
</repository>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* gnutls-ocsp.vapi — Vala 0.56's bundled gnutls.vapi has no OCSP bindings.
|
|
2
|
+
* This sibling vapi declares the minimal subset we need to wrap
|
|
3
|
+
* `gnutls_ocsp_resp_*` for OCSP-response parsing (RFC 6960).
|
|
4
|
+
*
|
|
5
|
+
* `.vapi` (vs `.vala`) is important: `.vapi` files are pure declarations
|
|
6
|
+
* mapping to existing C types. Putting these `cname = "struct …"` bindings
|
|
7
|
+
* in a `.vala` file makes valac try to *emit* the typedef, which collides
|
|
8
|
+
* with the typedef already present in `gnutls/ocsp.h`.
|
|
9
|
+
*
|
|
10
|
+
* Loaded via meson's `vala_args: ['--vapidir=<srcdir>/src/vala']`.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
[CCode (cheader_filename = "gnutls/ocsp.h", lower_case_cprefix = "gnutls_ocsp_")]
|
|
14
|
+
namespace GjsifyTlsOcsp {
|
|
15
|
+
|
|
16
|
+
[Compact]
|
|
17
|
+
[CCode (cname = "struct gnutls_ocsp_resp_int", free_function = "gnutls_ocsp_resp_deinit")]
|
|
18
|
+
public class Resp {
|
|
19
|
+
[CCode (cname = "gnutls_ocsp_resp_init")]
|
|
20
|
+
public static int init(out Resp resp);
|
|
21
|
+
|
|
22
|
+
[CCode (cname = "gnutls_ocsp_resp_import")]
|
|
23
|
+
public int import(ref GnuTLS.Datum data);
|
|
24
|
+
|
|
25
|
+
[CCode (cname = "gnutls_ocsp_resp_get_status")]
|
|
26
|
+
public int get_status();
|
|
27
|
+
|
|
28
|
+
[CCode (cname = "gnutls_ocsp_resp_get_produced")]
|
|
29
|
+
public time_t get_produced();
|
|
30
|
+
|
|
31
|
+
[CCode (cname = "gnutls_ocsp_resp_get_single")]
|
|
32
|
+
public int get_single(
|
|
33
|
+
uint indx,
|
|
34
|
+
out int digest,
|
|
35
|
+
out GnuTLS.Datum issuer_name_hash,
|
|
36
|
+
out GnuTLS.Datum issuer_key_hash,
|
|
37
|
+
out GnuTLS.Datum serial_number,
|
|
38
|
+
out uint cert_status,
|
|
39
|
+
out time_t this_update,
|
|
40
|
+
out time_t next_update,
|
|
41
|
+
out time_t revocation_time,
|
|
42
|
+
out uint revocation_reason);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* GjsifyTls — Vala/GObject bridge for GnuTLS APIs that Gio.TlsConnection
|
|
3
|
+
* does not surface to JS.
|
|
4
|
+
*
|
|
5
|
+
* Phase 1 scope (this file): OCSP-response parsing (RFC 6960).
|
|
6
|
+
*
|
|
7
|
+
* Status of GnuTLS bindings in Vala 0.56:
|
|
8
|
+
* - `gnutls.vapi` covers the core handshake / X.509 / pubkey surface
|
|
9
|
+
* but has *no* `gnutls_ocsp_*` declarations. We supply them in a
|
|
10
|
+
* sibling `gnutls-ocsp.vapi`, which the meson rule loads via
|
|
11
|
+
* `--vapidir`. `.vapi` files (vs `.vala`) declare existing C types
|
|
12
|
+
* without re-emitting the typedef — the `cname = "struct gnutls_…"`
|
|
13
|
+
* pattern that works in vapi headers crashes in `.vala` because
|
|
14
|
+
* valac there tries to define the type.
|
|
15
|
+
*
|
|
16
|
+
* Future scope (not in this file yet):
|
|
17
|
+
* - Session resumption: `gnutls_session_get_data2` / `set_data` —
|
|
18
|
+
* blocked on extracting the live `gnutls_session_t` from
|
|
19
|
+
* `Gio.TlsConnection`. Tracked in STATUS.md.
|
|
20
|
+
* - Channel binding: `gnutls_session_channel_binding` (TLS-Finished bytes
|
|
21
|
+
* for SCRAM-SHA-* SASL). Same gnutls_session_t blocker.
|
|
22
|
+
*
|
|
23
|
+
* The OCSP-response parser works on raw DER bytes (a Uint8Array on the
|
|
24
|
+
* JS side) and returns a plain GObject with the parsed fields. Consumers
|
|
25
|
+
* can fetch OCSP responses themselves (e.g. via @gjsify/fetch against the
|
|
26
|
+
* cert's Authority Information Access OCSP responder URL) and pass them
|
|
27
|
+
* here for validation.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
using GLib;
|
|
31
|
+
|
|
32
|
+
namespace GjsifyTls {
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* OcspResponseInfo — parsed result of {@link Tls.parse_ocsp_response}.
|
|
36
|
+
*
|
|
37
|
+
* Fields mirror the subset of RFC 6960 OCSPResponse we extract.
|
|
38
|
+
*/
|
|
39
|
+
public class OcspResponseInfo : GLib.Object {
|
|
40
|
+
/**
|
|
41
|
+
* `responseStatus` per RFC 6960 §4.2.1:
|
|
42
|
+
* 0 = successful
|
|
43
|
+
* 1 = malformedRequest
|
|
44
|
+
* 2 = internalError
|
|
45
|
+
* 3 = tryLater
|
|
46
|
+
* 5 = sigRequired
|
|
47
|
+
* 6 = unauthorized
|
|
48
|
+
*/
|
|
49
|
+
public int response_status { get; internal set; }
|
|
50
|
+
|
|
51
|
+
/** `producedAt` field (Unix seconds, 0 if unparseable). */
|
|
52
|
+
public int64 produced_at { get; internal set; }
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* `certStatus` per RFC 6960 §4.2.1:
|
|
56
|
+
* 0 = good
|
|
57
|
+
* 1 = revoked
|
|
58
|
+
* 2 = unknown
|
|
59
|
+
*/
|
|
60
|
+
public int cert_status { get; internal set; }
|
|
61
|
+
|
|
62
|
+
/** `thisUpdate` field (Unix seconds). */
|
|
63
|
+
public int64 this_update { get; internal set; }
|
|
64
|
+
|
|
65
|
+
/** `nextUpdate` field (Unix seconds, 0 if absent). */
|
|
66
|
+
public int64 next_update { get; internal set; }
|
|
67
|
+
|
|
68
|
+
/** `revocationTime` (Unix seconds, only when cert_status = 1). */
|
|
69
|
+
public int64 revocation_time { get; internal set; }
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* `revocationReason` per RFC 5280 §5.3.1 CRL reason codes.
|
|
73
|
+
* Only meaningful when cert_status = 1.
|
|
74
|
+
*/
|
|
75
|
+
public int revocation_reason { get; internal set; }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Tls — static helpers wrapping GnuTLS APIs not exposed by Gio.
|
|
80
|
+
*/
|
|
81
|
+
public class Tls : GLib.Object {
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* parse_ocsp_response:
|
|
85
|
+
* @bytes: DER-encoded OCSPResponse (RFC 6960)
|
|
86
|
+
*
|
|
87
|
+
* Parse an OCSP response and return its key fields. Returns %null
|
|
88
|
+
* if the bytes are not a valid OCSPResponse (init or import fails).
|
|
89
|
+
*
|
|
90
|
+
* On success the returned object's @response_status is filled even
|
|
91
|
+
* when @response_status != 0 (i.e. error responses); the per-cert
|
|
92
|
+
* fields (@cert_status, @this_update, …) are filled only when
|
|
93
|
+
* @response_status == 0 AND the response contains at least one
|
|
94
|
+
* SingleResponse — otherwise they are zero-initialised.
|
|
95
|
+
*/
|
|
96
|
+
public static OcspResponseInfo? parse_ocsp_response(uint8[] bytes) {
|
|
97
|
+
GjsifyTlsOcsp.Resp? resp = null;
|
|
98
|
+
if (GjsifyTlsOcsp.Resp.init(out resp) != 0 || resp == null) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
GnuTLS.Datum data = { (void*) bytes, (uint) bytes.length };
|
|
103
|
+
|
|
104
|
+
if (resp.import(ref data) != 0) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
var info = new OcspResponseInfo();
|
|
109
|
+
info.response_status = resp.get_status();
|
|
110
|
+
|
|
111
|
+
if (info.response_status != 0) {
|
|
112
|
+
// Non-successful response — per-cert fields not available.
|
|
113
|
+
return info;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
info.produced_at = (int64) resp.get_produced();
|
|
117
|
+
|
|
118
|
+
int digest;
|
|
119
|
+
GnuTLS.Datum issuer_name_hash;
|
|
120
|
+
GnuTLS.Datum issuer_key_hash;
|
|
121
|
+
GnuTLS.Datum serial_number;
|
|
122
|
+
uint cert_status;
|
|
123
|
+
time_t this_update;
|
|
124
|
+
time_t next_update;
|
|
125
|
+
time_t revocation_time;
|
|
126
|
+
uint revocation_reason;
|
|
127
|
+
|
|
128
|
+
// Read the first SingleResponse (index 0). Multi-cert
|
|
129
|
+
// responses are rare in OCSP-stapling contexts.
|
|
130
|
+
int rc = resp.get_single(
|
|
131
|
+
0,
|
|
132
|
+
out digest,
|
|
133
|
+
out issuer_name_hash,
|
|
134
|
+
out issuer_key_hash,
|
|
135
|
+
out serial_number,
|
|
136
|
+
out cert_status,
|
|
137
|
+
out this_update,
|
|
138
|
+
out next_update,
|
|
139
|
+
out revocation_time,
|
|
140
|
+
out revocation_reason);
|
|
141
|
+
|
|
142
|
+
if (rc == 0) {
|
|
143
|
+
info.cert_status = (int) cert_status;
|
|
144
|
+
info.this_update = (int64) this_update;
|
|
145
|
+
info.next_update = (int64) next_update;
|
|
146
|
+
info.revocation_time = (int64) revocation_time;
|
|
147
|
+
info.revocation_reason = (int) revocation_reason;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Touch the out-only datums once so valac doesn't drop them as
|
|
151
|
+
// unused; we don't surface them to JS yet — callers extract
|
|
152
|
+
// serial / issuer from the cert directly.
|
|
153
|
+
int _sink = digest;
|
|
154
|
+
if (_sink == -1) info.cert_status = info.cert_status;
|
|
155
|
+
|
|
156
|
+
return info;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|