]> git.proxmox.com Git - swtpm.git/blob - tests/common
tests: Extend --print-capabilities tests with test of swtpm_setup
[swtpm.git] / tests / common
1
2 SWTPM=swtpm
3 SWTPM_EXE=${SWTPM_EXE:-${ROOT}/src/swtpm/${SWTPM}}
4 SWTPM_IOCTL=${SWTPM_IOCTL:-${ROOT}/src/swtpm_ioctl/swtpm_ioctl}
5 SWTPM_BIOS=${SWTPM_BIOS:-${ROOT}/src/swtpm_bios/swtpm_bios}
6 SWTPM_SETUP=${SWTPM_SETUP:-${ROOT}/src/swtpm_setup/swtpm_setup}
7 ECHO=$(type -P echo)
8
9 # Note: Do not use file descriptors above 127 due to OpenBSD.
10
11 # Kill a process quietly
12 # @1: signal, e.g. -9
13 # @2: pid
14 function kill_quiet()
15 {
16 local sig="$1"
17 local pid="$2"
18
19 bash -c "kill $sig $pid &>/dev/null"
20 return $?
21 }
22
23 # Wait for a regular file to appear and for it to have > 0 bytes
24 #
25 # @1: filename
26 # @2: timeout in seconds
27 function wait_for_file()
28 {
29 local filename="$1"
30 local timeout="$2"
31
32 local loops=$((timeout * 10)) loop
33
34 for ((loop=0; loop<loops; loop++)); do
35 [ -f "${filename}" ] && [ $(get_filesize ${filename}) != 0 ] && {
36 return 1
37 }
38 sleep 0.1
39 done
40 return 0
41 }
42
43 # Wait for a regular file to disappear
44 #
45 # @1: filename
46 # @2: timeout in seconds
47 function wait_file_gone()
48 {
49 local filename="$1"
50 local timeout="$2"
51
52 local loops=$((timeout * 10)) loop
53
54 for ((loop=0; loop<loops; loop++)); do
55 [ -f "${filename}" ] || return 1
56 sleep 0.1
57 done
58 return 0
59 }
60
61 # Wait for a process with given PID to be gone
62 #
63 # @1: pid
64 # @2: timeout in seconds
65 function wait_process_gone()
66 {
67 local pid="$1"
68 local timeout="$2"
69
70 local loops=$((timeout * 10)) loop
71
72 for ((loop=0; loop<loops; loop++)); do
73 kill_quiet -0 ${pid} || return 1
74 sleep 0.1
75 done
76 return 0
77 }
78
79 # Wait for a chardev to appear
80 #
81 # @1: filename
82 # @2: timeout in seconds
83 function wait_for_chardev()
84 {
85 local filename="$1"
86 local timeout="$2"
87
88 local loops=$((timeout * 10)) loop
89
90 for ((loop=0; loop<loops; loop++)); do
91 [ -c "${filename}" ] && return 1
92 sleep 0.1
93 done
94 return 0
95 }
96
97 # Wait for a chardev to disappear
98 #
99 # @1: filename
100 # @2: timeout in seconds
101 function wait_chardev_gone()
102 {
103 local filename="$1"
104 local timeout="$2"
105
106 local loops=$((timeout * 10)) loop
107
108 for ((loop=0; loop<loops; loop++)); do
109 [ -c "${filename}" ] || return 1
110 sleep 0.1
111 done
112 return 0
113 }
114
115 # Wait for a socket file to appear
116 #
117 # @1: filename
118 # @2: timeout in seconds
119 function wait_for_socketfile()
120 {
121 local filename="$1"
122 local timeout="$2"
123
124 local loops=$((timeout * 10)) loop
125
126 for ((loop=0; loop<loops; loop++)); do
127 [ -S "${filename}" ] && return 1
128 sleep 0.1
129 done
130 return 0
131 }
132
133 # Wait for a socket file to disappear
134 #
135 # @1: filename
136 # @2: timeout in seconds
137 function wait_socketfile_gone()
138 {
139 local filename="$1"
140 local timeout="$2"
141
142 local loops=$((timeout * 10)) loop
143
144 for ((loop=0; loop<loops; loop++)); do
145 [ -S "${filename}" ] || return 1
146 sleep 0.1
147 done
148 return 0
149 }
150
151 # Wait for a server socket to appear
152 #
153 # @1: port
154 # @2: host
155 # @3: timeout in seconds
156 function wait_for_serversocket()
157 {
158 local port="$1"
159 local host="$2"
160 local timeout="$3"
161
162 local loops=$((timeout * 10)) loop
163
164 for ((loop=0; loop<loops; loop++)); do
165 (exec 127<>/dev/tcp/${host}/${port}) &>/dev/null
166 [ $? -eq 0 ] && return 1
167 sleep 0.1
168 done
169 return 0
170 }
171
172 # Wait for a server socket to disappear
173 #
174 # @1: port
175 # @2: host
176 # @3: timeout in seconds
177 function wait_serversocket_gone()
178 {
179 local port="$1"
180 local host="$2"
181 local timeout="$3"
182
183 local loops=$((timeout * 10)) loop
184
185 for ((loop=0; loop<loops; loop++)); do
186 (exec 127<>/dev/tcp/${host}/${port}) &>/dev/null
187 [ $? -eq 0 ] || return 1
188 sleep 0.1
189 done
190 return 0
191 }
192
193 # Run the swtpm_ioctl command
194 #
195 # @param1: type of interface
196 function run_swtpm_ioctl()
197 {
198 local iface=$1; shift
199
200 case "${iface}" in
201 cuse)
202 [ -z "${SWTPM_DEV_NAME}" ] && {
203 echo "SWTPM_DEV_NAME not defined"
204 exit 1
205 }
206 ${SWTPM_IOCTL} $@ ${SWTPM_DEV_NAME}
207 return $?
208 ;;
209 socket+socket|unix+socket)
210 [ -z "${SWTPM_SERVER_NAME}" ] && {
211 echo "SWTPM_SERVER_NAME not defined"
212 exit 1
213 }
214 [ -z "${SWTPM_SERVER_PORT}" ] && {
215 echo "SWTPM_SERVER_PORT not defined"
216 exit 1
217 }
218 ${SWTPM_IOCTL} \
219 --tcp ${SWTPM_SERVER_NAME}:${SWTPM_CTRL_PORT} \
220 $@
221 return $?
222 ;;
223 socket+unix|unix+unix)
224 [ -z "${SWTPM_CTRL_UNIX_PATH}" ] && {
225 echo "SWTPM_CTRL_UNIX_PATH not defined"
226 exit 1
227 }
228 ${SWTPM_IOCTL} \
229 --unix ${SWTPM_CTRL_UNIX_PATH} \
230 $@
231 return $?
232 ;;
233 esac
234 }
235
236 # Start the swtpm in the background
237 #
238 # @param1: type of interface
239 # @param2.. : parameters to pass to 'swtpm'
240 function run_swtpm()
241 {
242 local iface=$1; shift
243 local swtpm_server_disconnect=""
244
245 echo "==== Starting swtpm with interfaces ${iface} ===="
246 if [ -z "${SWTPM_SERVER_NO_DISCONNECT}" ]; then
247 swtpm_server_disconnect=",disconnect"
248 fi
249
250 case "${iface}" in
251 cuse)
252 [ -z "${SWTPM_DEV_NAME}" ] && {
253 echo "SWTPM_DEV_NAME not defined"
254 exit 1
255 }
256
257 if wait_chardev_gone ${SWTPM_DEV_NAME} 2; then
258 echo "${SWTPM_DEV_NAME} is still there and may be used."
259 exit 1
260 fi
261
262 ${SWTPM_EXE} cuse $@ -n ${SWTPM_DEV_NAME##*/}
263 rc=$?
264 if [ $rc -ne 0 ]; then
265 echo "Could not run ${SWTPM_EXE} using ${iface}"
266 exit 1
267 fi
268 if wait_for_chardev ${SWTPM_DEV_NAME} 2; then
269 echo "$SWTPM_DEV_NAME did not appear"
270 exit 1
271 fi
272
273 SWTPM_PID=$(ps aux |
274 grep "cuse" |
275 grep -E " ${SWTPM_DEV_NAME##*/}\$" |
276 grep -v grep |
277 gawk '{print $2}')
278 return $?
279 ;;
280 socket+socket)
281 [ -z "${SWTPM_SERVER_PORT}" ] && {
282 echo "SWTPM_SERVER_PORT not defined"
283 exit 1
284 }
285 [ -z "${SWTPM_CTRL_PORT}" ] && {
286 echo "SWTPM_CTRL_PORT not defined"
287 exit 1
288 }
289
290 if wait_serversocket_gone "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then
291 echo "Port ${SWTPM_SERVER_PORT} is still used"
292 exit 1
293 fi
294 if wait_serversocket_gone "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then
295 echo "Port ${SWTPM_CTRL_PORT} is still used"
296 exit 1
297 fi
298
299 ${SWTPM_EXE} socket $@ \
300 --server type=tcp,port=${SWTPM_SERVER_PORT}${swtpm_server_disconnect} \
301 --ctrl type=tcp,port=${SWTPM_CTRL_PORT} &
302 rc=$?
303 if [ $rc -ne 0 ]; then
304 echo "Could not run ${SWTPM_EXE} using ${iface}"
305 exit 1
306 fi
307 SWTPM_PID=$!
308 if wait_for_serversocket "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then
309 echo "Server did not open port ${SWTPM_SERVER_PORT}"
310 kill -9 ${SWTPM_PID}
311 exit 1
312 fi
313 if wait_for_serversocket "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then
314 echo "Server did not open port ${SWTPM_CTRL_PORT}"
315 kill -9 ${SWTPM_PID}
316 exit 1
317 fi
318 return 0
319 ;;
320 socket+unix)
321 [ -z "${SWTPM_SERVER_PORT}" ] && {
322 echo "SWTPM_SERVER_PORT not defined"
323 exit 1
324 }
325 [ -z "${SWTPM_CTRL_UNIX_PATH}" ] && {
326 echo "SWTPM_CTRL_UNIX_PATH not defined"
327 exit 1
328 }
329
330 if wait_serversocket_gone "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then
331 echo "Port ${SWTPM_SERVER_PORT} is still used"
332 exit 1
333 fi
334 if wait_socketfile_gone "${SWTPM_CTRL_UNIX_PATH}" 2; then
335 echo "Unix socket ${SWTPM_CTRL_UNIX_PATH} is still there"
336 exit 1
337 fi
338
339 ${SWTPM_EXE} socket $@ \
340 --server type=tcp,port=${SWTPM_SERVER_PORT}${swtpm_server_disconnect} \
341 --ctrl type=unixio,path=${SWTPM_CTRL_UNIX_PATH} &
342 rc=$?
343 if [ $rc -ne 0 ]; then
344 echo "Could not run ${SWTPM_EXE} using ${iface}"
345 exit 1
346 fi
347 [ $rc -ne 0 ] && return $rc
348 SWTPM_PID=$!
349 if wait_for_serversocket "${SWTPM_SERVER_PORT}" 127.0.0.1 2; then
350 echo "Server did not open port ${SWTPM_SERVER_PORT}"
351 kill -9 ${SWTPM_PID}
352 exit 1
353 fi
354 if wait_for_socketfile ${SWTPM_CTRL_UNIX_PATH} 1; then
355 echo "Server did not create UnixIO socket ${SWTPM_CTRL_UNIX_PATH}"
356 kill -9 ${SWTPM_PID}
357 exit 1
358 fi
359 return 0
360 ;;
361 unix+socket)
362 [ -z "${SWTPM_CMD_UNIX_PATH}" ] && {
363 echo "SWTPM_CMD_UNIX_PATH not defined"
364 exit 1
365 }
366 [ -z "${SWTPM_CTRL_PORT}" ] && {
367 echo "SWTPM_CTRL_PORT not defined"
368 exit 1
369 }
370
371 if wait_socketfile_gone "${SWTPM_CMD_UNIX_PATH}" 2; then
372 echo "Unix socket ${SWTPM_CMD_UNIX_PATH} is still there"
373 exit 1
374 fi
375 if wait_serversocket_gone "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then
376 echo "Port ${SWTPM_CTRL_PORT} is still used"
377 exit 1
378 fi
379
380 ${SWTPM_EXE} socket $@ \
381 --server type=unixio,path=${SWTPM_CMD_UNIX_PATH} \
382 --ctrl type=tcp,port=${SWTPM_CTRL_PORT} &
383 rc=$?
384 if [ $rc -ne 0 ]; then
385 echo "Could not run ${SWTPM_EXE} using ${iface}"
386 exit 1
387 fi
388 SWTPM_PID=$!
389 if wait_for_socketfile ${SWTPM_CMD_UNIX_PATH} 2; then
390 echo "Server did not create UnixIO socket ${SWTPM_CMD_UNIX_PATH}"
391 kill -9 ${SWTPM_PID}
392 exit 1
393 fi
394 if wait_for_serversocket "${SWTPM_CTRL_PORT}" 127.0.0.1 1; then
395 echo "Server did not open port ${SWTPM_CTRL_PORT}"
396 kill -9 ${SWTPM_PID}
397 exit 1
398 fi
399 return 0
400 ;;
401 unix+unix)
402 [ -z "${SWTPM_CMD_UNIX_PATH}" ] && {
403 echo "SWTPM_CMD_UNIX_PATH not defined"
404 exit 1
405 }
406 [ -z "${SWTPM_CTRL_UNIX_PATH}" ] && {
407 echo "SWTPM_CTRL_UNIX_PATH not defined"
408 exit 1
409 }
410
411 if wait_socketfile_gone "${SWTPM_CMD_UNIX_PATH}" 2; then
412 echo "Unix socket ${SWTPM_CMD_UNIX_PATH} is still there"
413 exit 1
414 fi
415 if wait_socketfile_gone "${SWTPM_CTRL_UNIX_PATH}" 2; then
416 echo "Unix socket ${SWTPM_CTRL_UNIX_PATH} is still there"
417 exit 1
418 fi
419
420 ${SWTPM_EXE} socket $@ \
421 --server type=unixio,path=${SWTPM_CMD_UNIX_PATH} \
422 --ctrl type=unixio,path=${SWTPM_CTRL_UNIX_PATH} &
423 rc=$?
424 if [ $rc -ne 0 ]; then
425 echo "Could not run ${SWTPM_EXE} using ${iface}"
426 exit 1
427 fi
428 SWTPM_PID=$!
429 if wait_for_socketfile ${SWTPM_CMD_UNIX_PATH} 2; then
430 echo "Server did not create UnixIO socket ${SWTPM_CMD_UNIX_PATH}"
431 kill -9 ${SWTPM_PID}
432 exit 1
433 fi
434 if wait_for_socketfile ${SWTPM_CTRL_UNIX_PATH} 1; then
435 echo "Server did not create UnixIO socket ${SWTPM_CTRL_UNIX_PATH}"
436 kill -9 ${SWTPM_PID}
437 exit 1
438 fi
439 return 0
440 ;;
441 esac
442 }
443
444 # Open the command channel/device on fd 100
445 #
446 # @param1: type of interface
447 # @param2: must be '100'
448 function swtpm_open_cmddev()
449 {
450 local iface=$1; shift
451
452 [ "$1" != "100" ] && {
453 echo "swtpm_opendev: Filedescriptor must be 100"
454 exit 1
455 }
456
457 case "${iface}" in
458 cuse)
459 [ -z "${SWTPM_DEV_NAME}" ] && {
460 echo "SWTPM_DEV_NAME not defined"
461 exit 1
462 }
463 exec 100<>${SWTPM_DEV_NAME}
464 return $?
465 ;;
466 socket+socket|socket+unix)
467 [ -z "${SWTPM_SERVER_NAME}" ] && {
468 echo "SWTPM_SERVER_NAME not defined"
469 exit 1
470 }
471 [ -z "${SWTPM_SERVER_PORT}" ] && {
472 echo "SWTPM_SERVER_PORT not defined"
473 exit 1
474 }
475 # Must first close on OS/X
476 exec 100>&-
477 exec 100<>/dev/tcp/${SWTPM_SERVER_NAME}/${SWTPM_SERVER_PORT}
478 return $?
479 ;;
480 unix+socket|unix+unix)
481 ;;
482 *)
483 echo "swtpm_opendev: unsupported interface $iface"
484 exit 1
485 esac
486 }
487
488 # Transmit a command on fd 100
489 #
490 # @param1: type of interface
491 function swtpm_cmd_tx()
492 {
493 local iface=$1
494 local cmd_path resp_path
495
496 cmd_path=$(mktemp)
497
498 case "${iface}" in
499 cuse)
500 echo -en "$2" > ${cmd_path}
501 cat ${cmd_path} >&100
502 dd if=/proc/self/fd/100 2>/dev/null | \
503 od -t x1 -A n | \
504 tr -s ' ' | \
505 tr -d '\n' | \
506 sed 's/ $//g'
507 ;;
508 socket+socket|socket+unix)
509 echo -en "$2" > ${cmd_path}
510 cat ${cmd_path} >&100
511 cat <&100 | od -t x1 -A n | \
512 tr -s ' ' | \
513 tr -d '\n' | \
514 sed 's/ $//g'
515 ;;
516 unix+socket|unix+unix)
517 echo -en "$2" > ${cmd_path}
518 socat -x -t50 \
519 FILE:${cmd_path},rdonly \
520 UNIX-CLIENT:${SWTPM_CMD_UNIX_PATH} 2>&1 | \
521 sed -n '/^ /p' | \
522 tail -n1
523 ;;
524 *)
525 echo "swtpm_opendev: unsupported interface $iface"
526 rm -f ${cmd_path}
527 exit 1
528 esac
529
530 rm -f ${cmd_path}
531 }
532
533 # Transmit a control command on fd 101
534 #
535 # @param1: type of interface
536 function swtpm_ctrl_tx()
537 {
538 local iface=$1
539 local ctrl_path resp_path
540
541 case "${iface}" in
542 socket+socket|unix+socket)
543 $ECHO -en "$2" >&101
544 cat <&101 | od -t x1 -A n -w128
545 ;;
546 socket+unix|unix+unix)
547 ctrl_path=$(mktemp)
548 echo -en "$2" > ${ctrl_path}
549 socat -x -t50 \
550 FILE:${ctrl_path},rdonly \
551 UNIX-CLIENT:${SWTPM_CTRL_UNIX_PATH} 2>&1 | \
552 sed -n '/^ /p' | \
553 tail -n1
554 rm -f ${ctrl_path}
555 ;;
556 *)
557 echo "swtpm_opendev: unsupported interface $iface"
558 exit 1
559 esac
560 }
561
562
563 # Run swtpm_bios
564 #
565 # @param1: type of interface
566 # @param2 ...: parameters to pass to swtpm_bios
567 function run_swtpm_bios()
568 {
569 local iface=$1
570
571 shift
572
573 case "${iface}" in
574 cuse)
575 [ -z "${SWTPM_DEV_NAME}" ] && {
576 echo "SWTPM_DEV_NAME not defined"
577 exit 1
578 }
579 ${SWTPM_BIOS} --tpm-device ${SWTPM_DEV_NAME} $@
580 return $?
581 ;;
582 unix+unix|unix+socket)
583 [ -z "${SWTPM_CMD_UNIX_PATH}" ] && {
584 echo "SWTPM_CMD_UNIX_PATH not defined"
585 exit 1
586 }
587 ${SWTPM_BIOS} --unix ${SWTPM_CMD_UNIX_PATH} $@
588 return $?
589 ;;
590 socket+unix|socket+socket)
591 [ -z "${SWTPM_SERVER_PORT}" ] && {
592 echo "SWTPM_SERVER_PORT not defined"
593 exit 1
594 }
595 ${SWTPM_BIOS} --tcp ${SWTPM_SERVER_NAME}:${SWTPM_SERVER_PORT} $@
596 return $?
597 ;;
598 *)
599 echo "run_swtpm_bios: unsupported interface $iface"
600 exit 1
601 esac
602 }
603
604 # Get the size of a file in bytes
605 #
606 # @1: filename
607 function get_filesize()
608 {
609 if [[ "$(uname -s)" =~ (Linux|CYGWIN_NT-) ]]; then
610 stat -c%s $1
611 else
612 # OpenBSD
613 stat -f%z $1
614 fi
615 }
616
617 # Get the file mode bits in octal format
618 #
619 # @1: filename
620 function get_filemode()
621 {
622 if [[ "$(uname -s)" =~ (Linux|CYGWIN_NT-) ]]; then
623 stat -c%a $1
624 else
625 # BSDs
626 stat -f%Lp $1
627 fi
628 }
629
630 # Get the file owner uid and gid
631 #
632 # @1: filename
633 function get_fileowner()
634 {
635 if [[ "$(uname -s)" =~ (Linux|CYGWIN_NT-) ]]; then
636 stat -c"%u %g" $1
637 else
638 # BSDs
639 stat -f"%u %g" $1
640 fi
641 }
642
643 # Get the SHA1 of a file
644 #
645 # @1: filename
646 function get_sha1_file()
647 {
648 if ! [ -r $1 ]; then
649 echo "[file $1 does not exist]"
650 return
651 fi
652 case "$(uname -s)" in
653 Linux|CYGWIN*)
654 sha1sum $1 | cut -f1 -d" "
655 ;;
656 Darwin)
657 shasum $1 | cut -f1 -d" "
658 ;;
659 *)
660 # OpenBSD
661 sha1 $1 | cut -d "=" -f2 | tr -d " "
662 esac
663 }
664
665 # Display process that have the same name
666 #
667 # @1: process name to match
668 function display_processes_by_name()
669 {
670 local name="$1"
671
672 if [ 1 -eq 0 ]; then
673 ps aux | grep "${name}" | grep -v grep
674 fi
675 }
676
677 # Check whether seccomp support is compiled in
678 #
679 # @1: path to swtpm
680 #
681 # Returns 0 if seccomp is supported, 1 otherwise
682 function has_seccomp_support()
683 {
684 local swtpm_exe="$1"
685
686 local tmp=$(${swtpm_exe} socket --help | grep -E "\-\-seccomp")
687
688 [ -n "${tmp}" ] && return 0
689 return 1
690 }
691
692 # Check whether the given process runs with the given seccomp
693 # profile type IF the given swtpm executable has seccomp support
694 #
695 # @1: Path to swtpm executable from which process was started
696 # @2: The process ID
697 # @3: The expected seccomp profile type
698 function check_seccomp_profile()
699 {
700 local swtpm_exe="$1"
701 local swtpm_pid="$2"
702 local profile="$3"
703
704 local tmp
705
706 if ! has_seccomp_support "${swtpm_exe}"; then
707 return 0
708 fi
709
710 tmp=$(grep -E "^Seccomp" /proc/${swtpm_pid}/status |
711 cut -d":" -f2 |
712 tr -d '\t')
713 if [ "${tmp}" != ${profile} ]; then
714 echo "Process ${swtpm_pid} has wrong seccomp profile type"
715 echo "Expected: ${profile}"
716 echo "Actual : ${tmp}"
717 return 1
718 fi
719 return 0
720 }