-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstart-node2.bat
More file actions
387 lines (363 loc) · 14.7 KB
/
Copy pathstart-node2.bat
File metadata and controls
387 lines (363 loc) · 14.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
@echo off
setlocal EnableExtensions DisableDelayedExpansion
if not defined PYTHONUTF8 set PYTHONUTF8=1
rem Windows equivalent of start-node2.sh.
rem
rem Configuration C (mTLS + OAuth 2.0) -- TR-10-SEC 12.3 RAAM=2.
rem
rem No Controller UI here: node 1 serves one on 5050 and shows every node
rem it discovers through the registry, this one included.
rem
rem Usage:
rem start-node2.bat [as-host] [as-port] [rds-host] [rds-port]
rem [--nap=N] [--rap=R] [--oaim=O] [--tct=T]
rem
rem %1 = OAuth 2.0 authorization server host (default XYZ-SNX00000)
rem %2 = OAuth 2.0 authorization server port (default 9443)
rem %3 = Registry host (default 127.0.0.1)
rem %4 = Registry registration port (default 8444; query = %4-1)
rem
rem --nap=N Node Access Policy. Config C pins NAP=2 per 9.2.
rem --rap=R Registry Access Policy: 0=HTTP, 1=server-TLS, 2=mTLS.
rem --oaim=O OAuth2 Audience ID Mode: 0=serial, 1=cert, 2=either.
rem --tct=T TLS Cert Type: 0=RSA (default), 1=ECDSA, 2=both
rem (presents whichever each client asks for).
rem
rem Requires hosts-file entries. This node addresses its peers by DNS name
rem because the certificates carry DNS SANs (XYZ-SNX000nn) and an IP literal
rem matches none of them. Add to C:\Windows\System32\drivers\etc\hosts
rem (as Administrator):
rem
rem 127.0.0.1 XYZ-SNX00000 registry + Authorization Server
rem 127.0.0.1 XYZ-SNX00001 node 1 + Controller UI
rem 127.0.0.1 XYZ-SNX00002 node 2
rem
rem Passing 127.0.0.1 as the registry host fails TLS verification under
rem --rap=1 or --rap=2 for the same reason -- pass XYZ-SNX00000.
rem
rem Set IPMX_CERT_ROOT to relocate the Certificates tree.
rem Set NMOS_PYTHON_EXE to override Python discovery.
set "SCRIPT_DIR=%~dp0"
pushd "%SCRIPT_DIR%" >nul || (
>&2 echo start-node2.bat: cannot enter "%SCRIPT_DIR%"
exit /b 1
)
set "AS_HOST=XYZ-SNX00000"
set "AS_PORT=9443"
set "RDS_HOST=127.0.0.1"
set "RDS_REG_PORT=8444"
rem Positionals are assigned in :parse_positionals below, which stops at the
rem first --option. Taking them as %~1..%~4 here meant `--rap=2` with no
rem positionals landed in AS_HOST and was then dropped from the option list:
rem accepted in appearance, ignored in effect.
rem In cmd.exe, %%1 treats an equals sign as an argument separator, so options
rem such as --tct=1 would arrive split. Keep %%* as text and walk it with FOR /F
rem instead, taking leading tokens as positionals only until the first --option.
set "REMAINING_ARGS=%*"
set "POS_INDEX=0"
:parse_positionals
if not defined REMAINING_ARGS goto positionals_done
if %POS_INDEX% GEQ 4 goto positionals_done
for /f "tokens=1,*" %%A in ("%REMAINING_ARGS%") do (
set "POS_ARG=%%~A"
set "POS_REST=%%B"
)
if "%POS_ARG:~0,2%"=="--" goto positionals_done
if %POS_INDEX%==0 set "AS_HOST=%POS_ARG%"
if %POS_INDEX%==1 set "AS_PORT=%POS_ARG%"
if %POS_INDEX%==2 set "RDS_HOST=%POS_ARG%"
if %POS_INDEX%==3 set "RDS_REG_PORT=%POS_ARG%"
set /a "POS_INDEX+=1" >nul
set "REMAINING_ARGS=%POS_REST%"
goto parse_positionals
:positionals_done
set "NAP=2"
set "RAP=0"
set "OAIM=0"
set "TCT=0"
:parse_options
if not defined REMAINING_ARGS goto options_done
for /f "tokens=1,*" %%A in ("%REMAINING_ARGS%") do (
set "ARG=%%~A"
set "REMAINING_ARGS=%%B"
)
if /i "%ARG:~0,6%"=="--nap=" (
set "NAP=%ARG:~6%"
goto parse_options
)
if /i "%ARG:~0,6%"=="--rap=" (
set "RAP=%ARG:~6%"
goto parse_options
)
if /i "%ARG:~0,7%"=="--oaim=" (
set "OAIM=%ARG:~7%"
goto parse_options
)
if /i "%ARG:~0,6%"=="--tct=" (
set "TCT=%ARG:~6%"
goto parse_options
)
>&2 echo start-node2.bat: unknown argument %ARG%
set "EXIT_CODE=64"
goto done
:options_done
if not "%NAP%"=="2" (
>&2 echo start-node2.bat: Config C ^(RAAM=2^) pins NAP=2; got --nap=%NAP%
set "EXIT_CODE=64"
goto done
)
call :require_port "as-port" "%AS_PORT%" 1 65535
if errorlevel 1 (
set "EXIT_CODE=64"
goto done
)
call :require_port "registration-port" "%RDS_REG_PORT%" 2 65535
if errorlevel 1 (
set "EXIT_CODE=64"
goto done
)
rem Checked above, so the arithmetic cannot fail here.
set /a "RDS_QUERY_PORT=RDS_REG_PORT - 1" >nul
rem Every value the command line can get wrong is settled here, before the
rem certificate probe below touches the disk. These same values are checked
rem again further down, by the blocks that also build a path or a flag out of
rem %CERTS% -- which is why they could not run until the probe had succeeded,
rem and why an unsupported --tct, --oaim or --rap answered "missing
rem ExampleRootCA.pem" and exited 66 (EX_NOINPUT) instead of naming the
rem argument and exiting 64 (EX_USAGE) on a machine whose PKI did not resolve.
rem
rem Those blocks are deliberately left exactly as they were. A value reaching
rem them is one this block already accepted, so nothing about a successful
rem start changes; their else-arms are now unreachable rather than wrong.
rem Kept rather than folded into this one because they are what assigns the
rem paths, and cmd expands an undefined variable to its own literal name --
rem so the "" infix the .sh uses would write %TCT_INFIX% into a filename here.
if not "%TCT%"=="0" if not "%TCT%"=="1" if not "%TCT%"=="2" (
>&2 echo start-node2.bat: unsupported --tct=%TCT%
set "EXIT_CODE=64"
goto done
)
if not "%OAIM%"=="0" if not "%OAIM%"=="1" if not "%OAIM%"=="2" (
>&2 echo start-node2.bat: unsupported --oaim=%OAIM%
set "EXIT_CODE=64"
goto done
)
if not "%RAP%"=="0" if not "%RAP%"=="1" if not "%RAP%"=="2" (
>&2 echo start-node2.bat: unsupported --rap=%RAP%
set "EXIT_CODE=64"
goto done
)
rem Prefer the certificate subset bundled inside this repository, so a
rem standalone clone of nmos-reference runs without the wider workspace PKI.
rem That subset ships only the serials the quick-start and tutorials use;
rem anything else falls back to the workspace-level Certificates\ tree.
rem An explicit IPMX_CERT_ROOT always wins over both.
set "CERT_PROBE=pem\ExampleDeviceServer.ABC.SNX00002.chain.pem"
if defined IPMX_CERT_ROOT (
set "CERT_ROOT=%IPMX_CERT_ROOT%"
) else if exist "%SCRIPT_DIR%Certificates\build.0\pem\ExampleDeviceServer.ABC.SNX00002.chain.pem" (
set "CERT_ROOT=%SCRIPT_DIR%Certificates"
) else if exist "%SCRIPT_DIR%..\Certificates\build.0\pem\ExampleDeviceServer.ABC.SNX00002.chain.pem" (
rem The workspace PKI carries serials this checkout does not ship, which is
rem how the IPMX security test suite supplies them, so the fallback stays --
rem but it announces itself. The silent version hid a missing serial through
rem an entire bring-up.
set "CERT_ROOT=%SCRIPT_DIR%..\Certificates"
>&2 echo start-node2.bat: %CERT_PROBE% is not in this checkout - using the workspace PKI.
) else (
>&2 echo start-node2.bat: missing build.0\%CERT_PROBE%
>&2 echo Searched "%SCRIPT_DIR%Certificates" and "%SCRIPT_DIR%..\Certificates".
>&2 echo Set IPMX_CERT_ROOT to a Certificates tree that carries it.
set "EXIT_CODE=66"
goto done
)
set "CERTS=%CERT_ROOT%\build.0"
rem Trust follows the certificate type, like the identities below: TR-10-SEC
rem 12.5 makes the TCT "common to all certificates and Root CAs of the
rem device", so a TCT=0 Node trusts the RSA root only, a TCT=1 Node the ECDSA
rem root only, and only a TCT=2 Node both.
if not "%TCT%"=="1" (
call :require_root "%CERTS%\ExampleRootCA.pem"
if errorlevel 1 (
set "EXIT_CODE=66"
goto done
)
)
if not "%TCT%"=="0" (
call :require_root "%CERTS%\ExampleRootCA.ec.pem"
if errorlevel 1 (
set "EXIT_CODE=66"
goto done
)
)
if "%TCT%"=="0" set "CA=%CERTS%\ExampleRootCA.pem"
if "%TCT%"=="1" set "CA=%CERTS%\ExampleRootCA.ec.pem"
rem TCT=2: one file holding both roots, so either certificate flavour validates
rem against a single --trustedRootCA. Prefer the copy that ships in
rem Certificates\ and derive one only when the resolved PKI has none -- a
rem workspace tree, or an IPMX_CERT_ROOT pointing elsewhere. Deriving
rem unconditionally wrote a single shared %TEMP% path from every launcher, so
rem two starting at once could have one truncate the file while the other's
rem Python was still reading it.
if "%TCT%"=="2" set "CA=%CERTS%\ExampleRootCA-bundle.pem"
if "%TCT%"=="2" if not exist "%CA%" (
call :derive_ca
if errorlevel 1 (
set "EXIT_CODE=66"
goto done
)
)
rem One --nodeCertificate/--nodeKey pair per identity. TR-10-SEC
rem TCT=2 ("Both") is the two-pair case: the listener holds an RSA
rem and an ECDSA identity at once and serves each client whichever
rem its ClientHello can verify. cmd has no arrays, so the pairs are
rem accumulated into one variable rather than iterated.
set "NODE_CERT_ARGS="
if not "%TCT%"=="1" set "NODE_CERT_ARGS=--nodeCertificate "%CERTS%\pem\ExampleDeviceServer.ABC.SNX00002.chain.pem" --nodeKey "%CERTS%\key\ExampleDeviceServer.ABC.SNX00002.key""
if not "%TCT%"=="0" set "NODE_CERT_ARGS=%NODE_CERT_ARGS% --nodeCertificate "%CERTS%\pem\ExampleDeviceServer.ABC.SNX00002.chain.ec.pem" --nodeKey "%CERTS%\key\ExampleDeviceServer.ABC.SNX00002.ec.key""
rem The client identities follow the same TCT: TR-10-SEC applies the
rem certificate type "to both endpoint and client accesses, and to server and
rem client certificates" (11), so a TCT=1 Node authenticates with its ECDSA
rem certificate and a TCT=2 Node holds both -- one pair per identity, as for
rem the listener above.
set "NODE_CLIENT_ARGS="
set "RDS_CLIENT_ARGS="
if not "%TCT%"=="1" set "NODE_CLIENT_ARGS=--nodeClientCertificate "%CERTS%\pem\ExampleDeviceClient.ABC.SNX00002.chain.pem" --nodeClientKey "%CERTS%\key\ExampleDeviceClient.ABC.SNX00002.key""
if not "%TCT%"=="0" set "NODE_CLIENT_ARGS=%NODE_CLIENT_ARGS% --nodeClientCertificate "%CERTS%\pem\ExampleDeviceClient.ABC.SNX00002.chain.ec.pem" --nodeClientKey "%CERTS%\key\ExampleDeviceClient.ABC.SNX00002.ec.key""
if not "%TCT%"=="1" set "RDS_CLIENT_ARGS=--rdsClientCertificate "%CERTS%\pem\ExampleDeviceClient.ABC.SNX00002.chain.pem" --rdsClientKey "%CERTS%\key\ExampleDeviceClient.ABC.SNX00002.key""
if not "%TCT%"=="0" set "RDS_CLIENT_ARGS=%RDS_CLIENT_ARGS% --rdsClientCertificate "%CERTS%\pem\ExampleDeviceClient.ABC.SNX00002.chain.ec.pem" --rdsClientKey "%CERTS%\key\ExampleDeviceClient.ABC.SNX00002.ec.key""
if "%OAIM%"=="0" (
set "OAIM_FLAG=serial"
) else if "%OAIM%"=="1" (
set "OAIM_FLAG=cert"
) else if "%OAIM%"=="2" (
set "OAIM_FLAG=either"
) else (
>&2 echo start-node2.bat: unsupported --oaim=%OAIM%
set "EXIT_CODE=64"
goto done
)
if "%RAP%"=="0" (
set "RDS_FLAGS=--rdsDisableTLS"
) else if "%RAP%"=="1" (
set "RDS_FLAGS="
) else if "%RAP%"=="2" (
set RDS_FLAGS=%RDS_CLIENT_ARGS%
) else (
>&2 echo start-node2.bat: unsupported --rap=%RAP%
set "EXIT_CODE=64"
goto done
)
call :find_python
if errorlevel 1 (
>&2 echo start-node2.bat: no Python 3.12+ interpreter found ^(checked NMOS_PYTHON_EXE, .venv, py -3, python.exe^).
>&2 echo Create .venv first, or install Python and make python.exe or py.exe available.
set "EXIT_CODE=9009"
goto done
)
echo Node SNX00002: Config C ^(mTLS + OAuth 2.0^), NAP=%NAP% RAP=%RAP% OAIM=%OAIM% TCT=%TCT%
"%PYTHON_EXE%" %PYTHON_SELECTOR% "%SCRIPT_DIR%nmos_node.py" ^
--nodeSerialNumber SNX00002 ^
--nodeAddr XYZ-SNX00002 ^
--nodePort 7052 ^
%NODE_CERT_ARGS% ^
--nodeTrustedRootCA "%CA%" ^
%NODE_CLIENT_ARGS% ^
--oauth2 ^
--oauth2Host "%AS_HOST%" ^
--oauth2Port "%AS_PORT%" ^
--oauth2TrustedRootCA "%CA%" ^
--oauth2ClientSecret secret ^
--oauth2ApiSelector realms/TR-10-SEC ^
--oauth2AudienceMode "%OAIM_FLAG%" ^
--oauth2ClientId Example.Company.Device.Client.ABC.SNX00002.example.com ^
--rdsHost "%RDS_HOST%" ^
--rdsRegistrationPort "%RDS_REG_PORT%" ^
--rdsQueryPort "%RDS_QUERY_PORT%" ^
%RDS_FLAGS% ^
--trustedRootCA "%CA%" ^
--debug-in-depth ^
--nodeConfig config_av_usb_tb_A
set "EXIT_CODE=%ERRORLEVEL%"
goto done
rem A trust root the selected TCT needs; missing is EX_NOINPUT, as in the .sh.
:require_root
if exist "%~1" exit /b 0
>&2 echo start-node2.bat: missing "%~1"
>&2 echo Set IPMX_CERT_ROOT to a Certificates tree that carries it.
exit /b 1
rem Build the combined trust store from the two roots of the resolved PKI,
rem both already confirmed present by :require_root.
rem A subroutine rather than an inline block: each line here is parsed as it
rem runs, so the CA path set below is visible to the copy that follows. Inside
rem a parenthesised block under DisableDelayedExpansion it would not be.
:derive_ca
rem A name of its own per run, so concurrent launchers cannot overwrite each
rem other's bundle while it is being read.
set "CA=%TEMP%\ExampleRootCA-bundle.%RANDOM%%RANDOM%.pem"
copy /b "%CERTS%\ExampleRootCA.pem" + "%CERTS%\ExampleRootCA.ec.pem" "%CA%" >nul
if errorlevel 1 (
>&2 echo start-node2.bat: cannot build a CA bundle from "%CERTS%"
exit /b 1
)
exit /b 0
rem Validate a port that came from the command line. set /a is no defence: it
rem evaluates a variable's VALUE as an expression, so a non-numeric port
rem silently becomes 0 and a derived port -1, which Python's argparse accepts as
rem a valid int. The minimum leaves room for the ports derived from this one.
:require_port
set "PORT_LABEL=%~1"
set "PORT_VALUE=%~2"
set "PORT_MIN=%~3"
set "PORT_MAX=%~4"
echo %PORT_VALUE%|findstr /r /c:"^[0-9][0-9]*$" >nul
if errorlevel 1 goto require_port_bad
rem Six characters or more cannot be a port, and dropping those here keeps the
rem numeric comparisons below away from values they cannot represent.
if not "%PORT_VALUE:~5,1%"=="" goto require_port_bad
if %PORT_VALUE% LSS %PORT_MIN% goto require_port_bad
if %PORT_VALUE% GTR %PORT_MAX% goto require_port_bad
exit /b 0
:require_port_bad
>&2 echo start-node2.bat: %PORT_LABEL% must be a whole number between %PORT_MIN% and %PORT_MAX%, got "%PORT_VALUE%"
exit /b 1
:find_python
rem Picking an interpreter is not the same as picking a usable one:
rem pyproject.toml requires >=3.12, while py.exe -3 selects the newest 3.x
rem installed and a bare python.exe is whatever came first on PATH. Both can be
rem older, and the failure then lands inside Python as a syntax or typing error
rem with no hint about the cause. Ask the interpreter before handing it the app.
call :pick_python
if errorlevel 1 exit /b 1
rem No < or > in the probe: cmd.exe can read them as redirection, and max()
rem expresses the same comparison without either character.
"%PYTHON_EXE%" %PYTHON_SELECTOR% -c "import sys; v = sys.version_info[:2]; sys.exit(0 if max(v, (3, 12)) == v else 1)" >nul 2>&1
if errorlevel 1 exit /b 2
exit /b 0
:pick_python
set "PYTHON_EXE="
set "PYTHON_SELECTOR="
if defined NMOS_PYTHON_EXE (
set "PYTHON_EXE=%NMOS_PYTHON_EXE%"
if defined NMOS_PYTHON_SELECTOR set "PYTHON_SELECTOR=%NMOS_PYTHON_SELECTOR%"
exit /b 0
)
if exist "%SCRIPT_DIR%.venv\Scripts\python.exe" (
set "PYTHON_EXE=%SCRIPT_DIR%.venv\Scripts\python.exe"
exit /b 0
)
where py.exe >nul 2>&1
if not errorlevel 1 (
set "PYTHON_EXE=py.exe"
set "PYTHON_SELECTOR=-3"
exit /b 0
)
where python.exe >nul 2>&1
if not errorlevel 1 (
set "PYTHON_EXE=python.exe"
exit /b 0
)
exit /b 1
:done
popd
endlocal & exit /b %EXIT_CODE%