U-Boot · source analysis

FIT hash와 signature 검증

필수 서명 실패와 hash 불일치는 image 검증을 실패시키지만, 선택 서명 실패는 표시만 하고 계속할 수 있다. 어느 조건에서 달라지는지 고정 소스로 읽는다.

이 글은 U-Boot v2026.07의 고정 코드에서 image 검증 분기를 설명한다. 실제 제품의 신뢰 정책과 key 관리·configuration 검증은 별도로 확인해야 한다.

Series
16 / 22
Baseline
v2026.07
Commit
ece349ade297
Source
boot/image-fit.c:1357–1419, 1435–1463 (분기·발췌 범위)

FIT image 검증은 어떤 실패를 거부하는가?

fit_image_verify()는 image data와 길이를 얻어 fit_image_verify_with_data()로 전달한다. 서명이 활성화된 빌드에서 이름에 @가 있으면 먼저 거부한다. 그 뒤 필수 signature, hash, 선택 signature, FDT 구조 오류는 서로 다른 분기로 처리된다. hash 통과는 출처 인증이 아니며, image 검증의 성공 반환과 configuration 서명 정책도 분리해서 읽어야 한다. boot/image-fit.c:1357–1419

검증 결과가 갈라지는 지점

그림 1. 필수 서명·hash·선택 서명의 결과 분기

좁은 화면에서는 그림을 좌우로 밀어 모든 분기를 볼 수 있습니다.

필수 서명 실패나 hash 불일치는 오류가 된다. 선택 서명 실패는 표시 후 계속한다. image 검증 결과와 configuration 검증은 별개다.

고정 원문 1309–1419행을 도식화했다. 그림 원본 크게 열기.

같은 “검증”이라는 말의 서로 다른 조건

image node에서 실제 반환을 바꾸는 조건
검사실행 조건실패했을 때근거
image 이름CONFIG_FIT_SIGNATURE 활성이고 이름에 @ 포함data 취득 전 fit_image_verify()가 0 반환1442–1462
data/sizefit_image_get_data()fit_image_verify()가 0 반환1450–1462
required signatureFIT_IMAGE_ENABLE_VERIFY이고 required key 정책 적용오류 분기, 0 반환1366–1372
hash node순회한 hash node에서 알고리즘을 먼저 읽음; !tools_build()이고 ignore이면 digest 비교 생략 가능알고리즘·값·digest 불일치면 0 반환1321–1354 · 1383–1388
선택 signature검증 활성화 및 verify_all 조건“−” 출력 후 계속, 이 실패만으로 0 반환하지 않음1389–1405
FDT 순회순회 결과가 truncated/badstructure오류 분기, 0 반환1408–1419

성공 반환의 의미

fit_image_verify_with_data()의 1은 이 함수에서 활성화된 image 검사들을 통과했다는 뜻이다. 선택 signature 실패는 표시만 할 수 있고, hash의 ignore도 U-Boot 실행 조건에서 적용될 수 있다. 따라서 이 반환값 하나를 “FIT 전체 구성이 인증됐다”로 바꾸어 읽지 않는다. 선택된 configuration의 검증 호출은 !fit_uname 경로에서 FIT_IMAGE_ENABLE_VERIFY && images->verify일 때 같은 파일의 별도 지점 2138–2149행에서 확인한다.

그림 2. FIT 안의 image·configuration과 FIT 밖의 공개키
configuration 서명 예시 FIT
/images/kernel-1data → hash-1의 digest
/images/fdt-1data → hash-1의 digest
/configurations/conf-1kernel·fdt 참조 → signature-1
configuration 서명은 구성 참조와 참조 image의 hash node를 포함한다. payload 자체는 hash 비교로 이어진다.
U-Boot control FDT/signature/key-…의 공개키와 required="image" 또는 required="conf" 정책이 파일에서 gd_fdt_blob()을 전달한다. control FDT 자체의 신뢰는 별도 부트 체인 조건이다.

동일한 image hash들이 맞아도 구성 참조를 바꾸면 다른 조합이 될 수 있다. 구성 서명과 참조 image hash의 관계는 U-Boot 공식 설명의 범위이며, 이 글의 고정 image-fit.c에는 configuration 검증 호출만 보인다.

원본 코드

아래 코드는 U-Boot v2026.07의 boot/image-fit.c에서 1411-1499줄을 그대로 가져온 것이다. 설명을 위해 실제 코드를 가짜 의사 코드로 바꾸지 않았다.

commitece349ade2973e220f524ce59e59711cc919263fanchor · L1435int fit_image_verify(const void *fit
1411	}
1412
1413	return 1;
1414
1415error:
1416	printf(" error!\n%s for '%s' hash node in '%s' image node\n",
1417	       err_msg, fit_get_name(fit, noffset, NULL),
1418	       fit_get_name(fit, image_noffset, NULL));
1419	return 0;
1420}
1421
1422/**
1423 * fit_image_verify - verify data integrity
1424 * @fit: pointer to the FIT format image header
1425 * @image_noffset: component image node offset
1426 *
1427 * fit_image_verify() goes over component image hash nodes,
1428 * re-calculates each data hash and compares with the value stored in hash
1429 * node.
1430 *
1431 * returns:
1432 *     1, if all hashes are valid
1433 *     0, otherwise (or on error)
1434 */
1435int fit_image_verify(const void *fit, int image_noffset)
1436{
1437	const char *name = fit_get_name(fit, image_noffset, NULL);
1438	const void	*data;
1439	size_t		size;
1440	char		*err_msg = "";
1441
1442	if (IS_ENABLED(CONFIG_FIT_SIGNATURE) && strchr(name, '@')) {
1443		/*
1444		 * We don't support this since libfdt considers names with the
1445		 * name root but different @ suffix to be equal
1446		 */
1447		err_msg = "Node name contains @";
1448		goto err;
1449	}
1450	/* Get image data and data length */
1451	if (fit_image_get_data(fit, image_noffset, &data, &size)) {
1452		err_msg = "Can't get image data/size";
1453		goto err;
1454	}
1455
1456	return fit_image_verify_with_data(fit, image_noffset, gd_fdt_blob(),
1457					  data, size);
1458
1459err:
1460	printf("error!\n%s in '%s' image node\n", err_msg,
1461	       fit_get_name(fit, image_noffset, NULL));
1462	return 0;
1463}
1464
1465/**
1466 * fit_all_image_verify - verify data integrity for all images
1467 * @fit: pointer to the FIT format image header
1468 *
1469 * fit_all_image_verify() goes over all images in the FIT and
1470 * for every images checks if all it's hashes are valid.
1471 *
1472 * returns:
1473 *     1, if all hashes of all images are valid
1474 *     0, otherwise (or on error)
1475 */
1476int fit_all_image_verify(const void *fit)
1477{
1478	int images_noffset;
1479	int noffset;
1480	int ndepth;
1481	int count;
1482
1483	/* Find images parent node offset */
1484	images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
1485	if (images_noffset < 0) {
1486		printf("Can't find images parent node '%s' (%s)\n",
1487		       FIT_IMAGES_PATH, fdt_strerror(images_noffset));
1488		return 0;
1489	}
1490
1491	/* Process all image subnodes, check hashes for each */
1492	printf("## Checking hash(es) for FIT Image at %08lx ...\n",
1493	       (ulong)fit);
1494	for (ndepth = 0, count = 0,
1495	     noffset = fdt_next_node(fit, images_noffset, &ndepth);
1496			(noffset >= 0) && (ndepth > 0);
1497			noffset = fdt_next_node(fit, noffset, &ndepth)) {
1498		if (ndepth == 1) {
1499			/*

기존 발췌와 실제 분기 위치

기존의 1411–1499행 발췌는 fit_image_verify() 정의와 호출을 포함하며, 첫 행은 앞 함수의 끝부분이다. required/optional 서명의 핵심 분기는 그보다 앞선 fit_image_verify_with_data()에 있다. 두 범위를 한 함수처럼 이어 붙이지 않는다.

required와 optional의 다른 실패 처리

아래 발췌는 U-Boot v2026.07의 원문 물리 행을 그대로 보여 준다. 먼저 필수 서명 검사를 통과하거나 비활성 조건을 지나야 하위 node를 순회한다. 선택 서명 실패는 표시만 하고, hash 실패는 오류로 간다. 원문 1357–1419행

int fit_image_verify_with_data(const void *fit, int image_noffset,
			       const void *key_blob, const void *data,
			       size_t size)
{
	int		noffset = 0;
	char		*err_msg = "";
	int verify_all = 1;
	int ret;

	/* Verify all required signatures */
	if (FIT_IMAGE_ENABLE_VERIFY &&
	    fit_image_verify_required_sigs(fit, image_noffset, data, size,
					   key_blob, &verify_all)) {
		err_msg = "Unable to verify required signature";
		goto error;
	}

	/* Process all hash subnodes of the component image node */
	fdt_for_each_subnode(noffset, fit, image_noffset) {
		const char *name = fit_get_name(fit, noffset, NULL);

		/*
		 * Check subnode name, must be equal to "hash".
		 * Multiple hash nodes require unique unit node
		 * names, e.g. hash-1, hash-2, etc.
		 */
		if (!strncmp(name, FIT_HASH_NODENAME,
			     strlen(FIT_HASH_NODENAME))) {
			if (fit_image_check_hash(fit, noffset, data, size,
						 &err_msg))
				goto error;
			puts("+ ");
		} else if (FIT_IMAGE_ENABLE_VERIFY && verify_all &&
				!strncmp(name, FIT_SIG_NODENAME,
					strlen(FIT_SIG_NODENAME))) {
			ret = fit_image_check_sig(fit, noffset, data, size,
						  gd_fdt_blob(), -1, &err_msg);

			/*
			 * Show an indication on failure, but do not return
			 * an error. Only keys marked 'required' can cause
			 * an image validation failure. See the call to
			 * fit_image_verify_required_sigs() above.
			 */
			if (ret)
				puts("- ");
			else
				puts("+ ");
		}
	}

	if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
		err_msg = "Corrupted or truncated tree";
		goto error;
	}

	return 1;

error:
	printf(" error!\n%s for '%s' hash node in '%s' image node\n",
	       err_msg, fit_get_name(fit, noffset, NULL),
	       fit_get_name(fit, image_noffset, NULL));
	return 0;

검증 함수와 보안 정책의 경계

이 파일에서 직접 보이는 분기와, 실제 부팅 정책에서 별도로 확인해야 할 질문을 나눈다. image hash만 맞는다고 image 출처나 선택된 configuration 전체를 인증한 것은 아니다. U-Boot 공식 FIT 서명 설명은 image hash와 서명·configuration 보호 범위를 구분한다.

함수 안의 판정과 상위 부팅 경로의 확인 항목
경계고정 소스에서 확인상위 경로에서 확인
key와 control FDTfit_image_verify()는 gd_fdt_blob()를 전달하고, required key 검사 실패는 오류로 간다. 1366–1372 · 1450–1457public key와 required 정책을 담은 control FDT가 신뢰 체인에 묶였는가? 이 함수만으로 그 보호를 증명할 수 없다.
검증 byte와 사용 byte이 함수의 입력 data,size가 실행되는 hash·서명 검사에 전달된다. 1357–1388상위 load/decompress/handoff가 실제로 소비한 byte가 검증 대상과 같은지, offset·size·buffer 변경 가능성을 추적한다.
configuration 선택image node 검증과, configuration을 선택한 경로에서의 fit_config_verify() 호출은 별도 지점이다. 2138–2149선택된 kernel·FDT·ramdisk 참조와 property가 어떤 서명 정책으로 보호되는지 해당 구현까지 확인한다. 명시적 image 이름을 받은 경로도 별도로 추적한다.
실패 뒤 fallback필수 서명/hash 오류는 이 image 검증에서 0을 돌려준다. 1366–1419호출자가 오류 뒤 서명 없는 다른 image 형식이나 configuration으로 진행하지 않는지 실제 boot command 경로를 확인한다.

표의 오른쪽 항목은 이 파일에서 보안이 자동으로 보장된다는 주장이 아니라 제품별 부트 경로에서 검증할 계약이다. U-Boot 공식 설명도 required 서명에 의존할 때 legacy image 경로를 함께 검토하도록 안내한다.

입력과 신뢰 경계

대상여기서 확인하는 값이 페이지에서 단정하지 않는 것
FIT image nodedata, size, 하위 hash/signature nodeconfiguration 전체의 선택 정책
key blob필수 서명 검사에 전달되는 control FDTcontrol FDT 자체의 신뢰 확보 방법
검증 결과활성화된 image 검사 기준 1 또는 0선택 서명 실패가 부팅 거부라는 주장

근거: 1357–1419 · 1435–1457.

반환 0과 계속 진행을 나누기

필수 key 서명 실패, hash 오류, FDT truncated/badstructure는 fit_image_verify_with_data()의 오류 경로에서 0을 반환한다. 선택 서명 실패는 “−”로 표시하고 순회를 계속한다. 1357–1419

fit_image_get_data()가 실패하면 호출자인 fit_image_verify()가 err로 가며, 실제 return 0은 1462행에 있다. 함수의 0 반환과 최종 부팅 거부는 다르므로, 상위 호출자가 fallback 없이 멈추는지도 대조한다.

검증 경계를 실제로 관찰하기

mkimage -l로 FIT의 image·configuration·hash·signature node를 기록하고, 같은 테스트에서 image verifier 반환, configuration verifier 결과, 최종 boot handoff 여부를 따로 남긴다. 반환 하나만으로 control FDT의 신뢰나 실행 byte의 동일성을 판정하지 않는다.

테스트 FIT의 node 목록
mkimage -l test.itb

가능한 빌드에서는 공식 FIT 서명 문서의 sandbox vboot 테스트를 출발점으로 삼고, 제품의 required key·legacy image 설정과 실제 loader 경로를 별도로 재현한다.

잘못된 입력을 넣었을 때 확인할 결과

변경한 입력기록할 분기상위 경로 질문
payload 한 byte 변경hash 검사 반환·오류 문자열최종 handoff가 차단되는가?
required 서명 제거 또는 손상required 검사 반환과 image 검증 0다른 unsigned image로 fallback하는가?
선택 서명만 손상“−” 출력과 함수 반환을 분리해 기록configuration의 별도 정책은 무엇인가?
configuration property 변경image 검증과 configuration 검증 결과를 각각 기록선택된 kernel/FDT 참조가 보호되는가?

테스트 FIT와 control FDT의 정확한 정책을 함께 기록한다. 이 표는 고정 함수의 모든 결과를 단정하지 않고, 경계 밖의 실패를 드러내기 위한 비교 설계다.

고정 원문과 정책 설명

U-Boot v2026.07 boot/image-fit.c:1309–1463 · configuration 검증 호출 2138–2149 · U-Boot FIT Signature Verification. 코드 기준 태그의 peeled commit: ece349ade2973e220f524ce59e59711cc919263f.