[edk2-devel] Interpretation of specification
Laszlo Ersek
lersek at redhat.com
Wed Jan 8 11:24:13 UTC 2020
(+James)
On 01/07/20 19:13, Eugene Khoruzhenko wrote:
> I think I may have found the problem. I can write the
> file_name.signed created by your scripts in NT32 emulated environment
> and in EDKII on Minnow board that I build myself. However, I cannot
> write the file_name.signed on a commercial device. I can write the
> same authenticate variable with the same Name/GUID and same cert/key
> on a device when I create the payload in a UEFI Shell app. So the
> only difference is creating the signed payload by sbvarsign in Ubuntu
> vs doing it in UEFI. I compared both the working and non-working
> payloads and the main difference I see is in the timestamp. For some
> reason sbvarsign writes the Year as 0x0078 (120) vs the UEFI app
> writing 0x07e4 (2020). The month/day/hour/min seems to be OK, but the
> year is really off in the sbvarsign's payload. I cannot prove it, but
> I think the commercial firmware may be having a sanity check for the
> timestamp date/time, e.g. compare with the device manufacture date.
> Since sbvarsign does not allow setting a timestamp separately, I
> cannot force it to create a payload with the correct year.
That looks like a bug in sbvarsign. In UEFI-2.8, the EFI_TIME structure
is defined under 8.3 "Time Services" / GetTime(). The Year field is
given like this:
UINT16 Year; // 1900 - 9999
The comment indicates the valid range. It does not indicate that the
value stored should be relative to the year 1900 (which is what
sbvarsign appears to assume; 2020-1900=120).
The UEFI application likely uses GetTime(), for populating
"EFI_VARIABLE_AUTHENTICATION_2.TimeStamp" with the current time (which
is prescribed in 8.2.2 "Using the EFI_VARIABLE_AUTHENTICATION_2
descriptor").
After GetTime() returns successfully, the application may still need to
manually ensure that "Pad1, Nanosecond, TimeZone, Daylight and Pad2" are
zeroed. This could involve timezone translation (to the required UTC),
which in some cases could even imply a change to the Year field. But
that doesn't change the fact that GetTime() initally places an absolute
year number in the Year field, and not one relative to 1900.
Let me see the "sbsigntool" source code:
https://git.kernel.org/pub/scm/linux/kernel/git/jejb/sbsigntools.git
(Repository URL via
<https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=920013>.)
Yup, here's the bug (at current master, that is, commit 0dc3d4b5210d,
"Fix PE/COFF checksum calculation", 2019-07-27):
https://git.kernel.org/pub/scm/linux/kernel/git/jejb/sbsigntools.git/tree/src/sbvarsign.c?id=0dc3d4b5210dae158651d058f7ac68a9f178ae84#n215
Quote:
199 static int set_timestamp(EFI_TIME *timestamp)
200 {
201 struct tm *tm;
202 time_t t;
203
204 time(&t);
205
206 tm = gmtime(&t);
207 if (!tm) {
208 perror("gmtime");
209 return -1;
210 }
211
212 /* copy to our EFI-specific time structure. Other fields (Nanosecond,
213 * TimeZone, Daylight and Pad) are defined to be zero */
214 memset(timestamp, 0, sizeof(*timestamp));
215 timestamp->Year = tm->tm_year;
216 timestamp->Month = tm->tm_mon;
217 timestamp->Day = tm->tm_mday;
218 timestamp->Hour = tm->tm_hour;
219 timestamp->Minute = tm->tm_min;
220 timestamp->Second = tm->tm_sec;
221
222 return 0;
223 }
Please refer to POSIX for time(), gmtime(), and "struct tm":
https://pubs.opengroup.org/onlinepubs/9699919799/functions/time.html
https://pubs.opengroup.org/onlinepubs/9699919799/functions/gmtime.html
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/time.h.html
Quoting the last reference:
> The <time.h> header shall declare the tm structure, which shall
> include at least the following members:
>
> int tm_sec Seconds [0,60].
> int tm_min Minutes [0,59].
> int tm_hour Hour [0,23].
> int tm_mday Day of month [1,31].
> int tm_mon Month of year [0,11].
> int tm_year Years since 1900.
> int tm_wday Day of week [0,6] (Sunday =0).
> int tm_yday Day of year [0,365].
> int tm_isdst Daylight Savings flag.
That is, field "tm_year" is relative to 1900.
The bug is therefore in set_timestamp(), on line 215. It should be
timestamp->Year = 1900 + tm->tm_year;
The bug goes back to commit 953b00481f39 ("sbvarsign: First cut of a
variable-signing tool", 2012-08-02).
(Otherwise, gmtime() is a good choice, because it gives us UTC at once,
which is what EFI_VARIABLE_AUTHENTICATION_2 requires, per UEFI spec
("GMT").)
I don't know where sbsigntools development occurs (mailing list, bug
tracker, ...). For now, I'm CC'ing James. (The git repo lives in his
space on <git.kernel.org>.)
James, the original thread on edk2-devel is here:
* [edk2-devel] Interpretation of specification
https://edk2.groups.io/g/devel/message/49402
Thanks,
Laszlo
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#53012): https://edk2.groups.io/g/devel/message/53012
Mute This Topic: https://groups.io/mt/36573446/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-
More information about the edk2-devel-archive
mailing list