github.com/linuxboot/fiano@v1.2.0/pkg/intel/metadata/fit/ent_startup_ac_module_entry.go (about) 1 // Copyright 2017-2021 the LinuxBoot Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package fit 6 7 import ( 8 "crypto/rsa" 9 "encoding/binary" 10 "encoding/json" 11 "fmt" 12 "io" 13 "math/big" 14 "reflect" 15 16 "github.com/linuxboot/fiano/pkg/intel/metadata/fit/check" 17 "github.com/xaionaro-go/bytesextra" 18 ) 19 20 // EntrySACM represents a FIT entry of type "Startup AC Module Entry" (0x02) 21 type EntrySACM struct{ EntryBase } 22 23 var _ EntryCustomGetDataSegmentSizer = (*EntrySACM)(nil) 24 25 func (entry *EntrySACM) CustomGetDataSegmentSize(firmware io.ReadSeeker) (uint64, error) { 26 offset, err := entry.Headers.getDataSegmentOffset(firmware) 27 if err != nil { 28 return 0, fmt.Errorf("unable to detect data segment offset: %w", err) 29 } 30 31 // See point "7" of "2.7" of the specification: the size field is 32 // always zero. So we parsing the size from it's data right now: 33 var size uint32 34 size, err = EntrySACMParseSizeFrom(firmware, offset) 35 if err != nil { 36 return 0, fmt.Errorf("unable to detect data segment size: %w", err) 37 } 38 return uint64(size), nil 39 } 40 41 var _ EntryCustomRecalculateHeaderser = (*EntrySACM)(nil) 42 43 func (entry *EntrySACM) CustomRecalculateHeaders() error { 44 // See 4.4.7 of the FIT specification. 45 entry.Headers.Size.SetUint32(0) 46 return nil 47 } 48 49 // See the section "A.1" of the specification 50 // "Intel ® Trusted Execution Technology (Intel ® TXT)" 51 // https://www.intel.com/content/www/us/en/software-developers/txt-software-development-guide.html 52 53 // EntrySACMDataInterface is the interface of a startup AC module 54 // data (of any version) 55 type EntrySACMDataInterface interface { 56 io.ReadWriter 57 io.ReaderFrom 58 io.WriterTo 59 60 // Field getters: 61 62 GetModuleType() ACModuleType 63 GetModuleSubType() ACModuleSubType 64 GetHeaderLen() SizeM4 65 GetHeaderVersion() ACModuleHeaderVersion 66 GetChipsetID() ACChipsetID 67 GetFlags() ACFlags 68 GetModuleVendor() ACModuleVendor 69 GetDate() BCDDate 70 GetSize() SizeM4 71 GetTXTSVN() TXTSVN 72 GetSESVN() SESVN 73 GetCodeControl() CodeControl 74 GetErrorEntryPoint() ErrorEntryPoint 75 GetGDTLimit() GDTLimit 76 GetGDTBasePtr() GDTBasePtr 77 GetSegSel() SegSel 78 GetEntryPoint() EntryPoint 79 GetReserved2() [64]byte 80 GetKeySize() SizeM4 81 GetScratchSize() SizeM4 82 GetRSAPubKey() rsa.PublicKey 83 GetRSAPubExp() uint32 84 GetRSASig() []byte 85 GetScratch() []byte 86 87 // Auxiliary methods: 88 RSASigBinaryOffset() uint64 89 90 // DateBinaryOffset returns the offset of the field 'Date' 91 // relatively to the beginning of the structure in the binary 92 // format (see 'encoding/binary'). 93 DateBinaryOffset() uint 94 } 95 96 // ACModuleType defines the type of AC module 97 type ACModuleType uint16 98 99 // ACModuleSubType defines the subtype of AC module (0 - TXT ACM; 1 - S-ACM) 100 type ACModuleSubType uint16 101 102 // ACModuleHeaderVersion defines module format version: 103 // * 0.0 – for SINIT ACM before 2017 104 // * 3.0 – for SINIT ACM of converge of BtG and TXT 105 type ACModuleHeaderVersion uint32 106 107 const ( 108 // ACHeaderVersion0 is version "0.0 – for SINIT ACM before 2017" 109 ACHeaderVersion0 = ACModuleHeaderVersion(0x00000000) 110 111 // ACHeaderVersion3 is version "3.0 – for SINIT ACM of converge of BtG and TXT" 112 ACHeaderVersion3 = ACModuleHeaderVersion(0x00030000) 113 ) 114 115 func (ver ACModuleHeaderVersion) GoString() string { 116 return fmt.Sprintf("0x%08X", ver) 117 } 118 119 // ACChipsetID defines the module release identifier 120 type ACChipsetID uint16 121 122 // ACFlags defines the module-specific flags 123 type ACFlags uint16 124 125 // ACModuleVendor defines the module vendor identifier 126 type ACModuleVendor uint32 127 128 // BCDDate is a date in format ("year.month.day") 129 type BCDDate uint32 130 131 // SizeM4 is a size in multiples of four bytes 132 type SizeM4 uint32 133 134 // Size return the size in bytes 135 func (size SizeM4) Size() uint64 { return uint64(size) << 2 } 136 func (size SizeM4) String() string { return fmt.Sprintf("%d*4", uint32(size)) } 137 func (size *SizeM4) SetSize(v uint64) { *size = SizeM4(v >> 2) } 138 139 // TXTSVN is the TXT Security Version Number 140 type TXTSVN uint16 141 142 // SESVN is the Software Guard Extensions (Secure Enclaves) Security Version Number 143 type SESVN uint16 144 145 // CodeControl is the authenticated code control flags 146 type CodeControl uint32 147 148 // ErrorEntryPoint is the error response entry point offset (bytes) 149 type ErrorEntryPoint uint32 150 151 // Pointer returns the value of ErrorEntryPoint as a pointer which 152 // could be used for pointer arithmetics. 153 func (ptr ErrorEntryPoint) Pointer() uint64 { return uint64(ptr) } 154 155 // GDTLimit is the GDT limit (defines last byte of GDT) 156 type GDTLimit uint32 157 158 // GDTBasePtr is the GDT base pointer offset (bytes) 159 type GDTBasePtr uint32 160 161 // Offset returns the GDTBasePtr value as a pointer which 162 // could be used for pointer arithmetics. 163 func (ptr GDTBasePtr) Offset() uint64 { return uint64(ptr) } 164 165 // SegSel is the segment selector initializer 166 type SegSel uint32 167 168 // EntryPoint is the authenticated code entry point offset (bytes) 169 type EntryPoint uint32 170 171 // EntrySACMDataCommon is the common part from the beginning of a startup AC module 172 // entry of any version. 173 type EntrySACMDataCommon struct { 174 ModuleType ACModuleType 175 ModuleSubType ACModuleSubType 176 HeaderLen SizeM4 177 HeaderVersion ACModuleHeaderVersion 178 ChipsetID ACChipsetID 179 Flags ACFlags 180 ModuleVendor ACModuleVendor 181 Date BCDDate 182 Size SizeM4 183 TXTSVN TXTSVN 184 SESVN SESVN 185 CodeControl CodeControl 186 ErrorEntryPoint ErrorEntryPoint 187 GDTLimit GDTLimit 188 GDTBasePtr GDTBasePtr 189 SegSel SegSel 190 EntryPoint EntryPoint 191 Reserved2 [64]byte 192 KeySize SizeM4 193 ScratchSize SizeM4 194 } 195 196 var entrySACMDataCommonSize = uint(binary.Size(EntrySACMDataCommon{})) 197 198 // Read parses the ACM common headers 199 func (entryData *EntrySACMDataCommon) Read(b []byte) (int, error) { 200 n, err := entryData.ReadFrom(bytesextra.NewReadWriteSeeker(b)) 201 return int(n), err 202 } 203 204 // ReadFrom parses the ACM common headers 205 func (entryData *EntrySACMDataCommon) ReadFrom(r io.Reader) (int64, error) { 206 err := binary.Read(r, binary.LittleEndian, entryData) 207 if err != nil { 208 return -1, err 209 } 210 return int64(entrySACMDataCommonSize), nil 211 } 212 213 // Write compiles the SACM common headers into a binary representation 214 func (entryData *EntrySACMDataCommon) Write(b []byte) (int, error) { 215 n, err := entryData.WriteTo(bytesextra.NewReadWriteSeeker(b)) 216 return int(n), err 217 } 218 219 // WriteTo compiles the SACM common headers into a binary representation 220 func (entryData *EntrySACMDataCommon) WriteTo(w io.Writer) (int64, error) { 221 err := binary.Write(w, binary.LittleEndian, entryData) 222 if err != nil { 223 return -1, err 224 } 225 return int64(entrySACMDataCommonSize), nil 226 } 227 228 // GetModuleType returns the type of AC module 229 func (entryData *EntrySACMDataCommon) GetModuleType() ACModuleType { return entryData.ModuleType } 230 231 // GetModuleSubType returns the subtype of AC module (0 - TXT ACM; 1 - S-ACM) 232 func (entryData *EntrySACMDataCommon) GetModuleSubType() ACModuleSubType { 233 return entryData.ModuleSubType 234 } 235 236 // GetHeaderLen returns HeaderLen field value 237 func (entryData *EntrySACMDataCommon) GetHeaderLen() SizeM4 { return entryData.HeaderLen } 238 239 // GetHeaderVersion returns module format version: 240 // * 0.0 – for SINIT ACM before 2017 241 // * 3.0 – for SINIT ACM of converge of BtG and TXT 242 func (entryData *EntrySACMDataCommon) GetHeaderVersion() ACModuleHeaderVersion { 243 return entryData.HeaderVersion 244 } 245 246 // GetChipsetID returns ChipsetID field value 247 func (entryData *EntrySACMDataCommon) GetChipsetID() ACChipsetID { return entryData.ChipsetID } 248 249 // GetFlags returns Flags field value (the module-specific flags) 250 func (entryData *EntrySACMDataCommon) GetFlags() ACFlags { return entryData.Flags } 251 252 // GetModuleVendor returns ModuleVendor field value 253 func (entryData *EntrySACMDataCommon) GetModuleVendor() ACModuleVendor { return entryData.ModuleVendor } 254 255 // GetDate returns Date field value ("year.month.day") 256 func (entryData *EntrySACMDataCommon) GetDate() BCDDate { return entryData.Date } 257 258 // GetSize returns Size field value (the size in multiples of four bytes) 259 func (entryData *EntrySACMDataCommon) GetSize() SizeM4 { return entryData.Size } 260 261 // GetTXTSVN returns TXT security version number 262 func (entryData *EntrySACMDataCommon) GetTXTSVN() TXTSVN { return entryData.TXTSVN } 263 264 // GetSESVN returns Software Guard Extensions (Secure Enclaves) Security Version Number 265 func (entryData *EntrySACMDataCommon) GetSESVN() SESVN { return entryData.SESVN } 266 267 // GetCodeControl returns the authenticated code control flags 268 func (entryData *EntrySACMDataCommon) GetCodeControl() CodeControl { return entryData.CodeControl } 269 270 // GetErrorEntryPoint returns error entry point field value 271 func (entryData *EntrySACMDataCommon) GetErrorEntryPoint() ErrorEntryPoint { 272 return entryData.ErrorEntryPoint 273 } 274 275 // GetGDTLimit returns GDTLimit field value 276 func (entryData *EntrySACMDataCommon) GetGDTLimit() GDTLimit { return entryData.GDTLimit } 277 278 // GetGDTBasePtr returns the GDT base pointer offset (bytes) 279 func (entryData *EntrySACMDataCommon) GetGDTBasePtr() GDTBasePtr { return entryData.GDTBasePtr } 280 281 // GetSegSel the segment selector initializer 282 func (entryData *EntrySACMDataCommon) GetSegSel() SegSel { return entryData.SegSel } 283 284 // GetEntryPoint returns the authenticated code entry point offset (bytes) 285 func (entryData *EntrySACMDataCommon) GetEntryPoint() EntryPoint { return entryData.EntryPoint } 286 287 // GetReserved2 returns the Reserved2 field value 288 func (entryData *EntrySACMDataCommon) GetReserved2() [64]byte { return entryData.Reserved2 } 289 290 // GetKeySize returns the KeySize field value (the size in multiples of four bytes) 291 func (entryData *EntrySACMDataCommon) GetKeySize() SizeM4 { return entryData.KeySize } 292 293 // GetScratchSize returns the ScratchSize field value (the size in multiples of four bytes) 294 func (entryData *EntrySACMDataCommon) GetScratchSize() SizeM4 { return entryData.ScratchSize } 295 296 // GetRSAPubKey returns the RSA public key 297 func (entryData *EntrySACMDataCommon) GetRSAPubKey() rsa.PublicKey { return rsa.PublicKey{} } 298 299 // GetRSAPubExp returns the RSA exponent 300 func (entryData *EntrySACMDataCommon) GetRSAPubExp() uint32 { return 0 } 301 302 // GetRSASig returns the RSA signature. 303 func (entryData *EntrySACMDataCommon) GetRSASig() []byte { return nil } 304 305 // RSASigBinaryOffset returns the RSA signature offset 306 func (entryData *EntrySACMDataCommon) RSASigBinaryOffset() uint64 { return 0 } 307 308 // GetScratch returns the Scratch field value 309 func (entryData *EntrySACMDataCommon) GetScratch() []byte { return nil } 310 311 // HeaderVersionBinaryOffset returns the offset of the field 'HeaderVersion' 312 // relatively to the beginning of the structure in the binary 313 // format (see 'encoding/binary'). 314 func (entryData EntrySACMDataCommon) HeaderVersionBinaryOffset() uint { 315 return 8 316 } 317 318 // DateBinaryOffset returns the offset of the field 'Date' 319 // relatively to the beginning of the structure in the binary 320 // format (see 'encoding/binary'). 321 func (entryData EntrySACMDataCommon) DateBinaryOffset() uint { 322 return 20 323 } 324 325 // SizeBinaryOffset returns the offset of the field 'Size' 326 // relatively to the beginning of the structure in the binary 327 // format (see 'encoding/binary'). 328 func (entryData EntrySACMDataCommon) SizeBinaryOffset() uint { 329 return 24 330 } 331 332 // TXTSVNBinaryOffset returns the offset of the field 'TXTSVN' 333 // relatively to the beginning of the structure in the binary 334 // format (see 'encoding/binary'). 335 func (entryData *EntrySACMDataCommon) TXTSVNBinaryOffset() uint64 { 336 return 28 337 } 338 339 // KeySizeBinaryOffset returns the offset of the field 'KeySize' 340 // relatively to the beginning of the structure in the binary 341 // format (see 'encoding/binary'). 342 func (entryData EntrySACMDataCommon) KeySizeBinaryOffset() uint { 343 return 120 344 } 345 346 // EntrySACMData0 is the structure for ACM of version 0.0. 347 type EntrySACMData0 struct { 348 EntrySACMDataCommon 349 350 RSAPubKey [256]byte 351 RSAPubExp [4]byte 352 RSASig [256]byte 353 Scratch [572]byte 354 } 355 356 var entrySACMData0Size = uint(binary.Size(EntrySACMData0{})) 357 358 // Read parses the ACM v0 headers 359 func (entryData *EntrySACMData0) Read(b []byte) (int, error) { 360 n, err := entryData.ReadFrom(bytesextra.NewReadWriteSeeker(b)) 361 return int(n), err 362 } 363 364 // ReadFrom parses the ACM v0 headers 365 func (entryData *EntrySACMData0) ReadFrom(r io.Reader) (int64, error) { 366 err := binary.Read(r, binary.LittleEndian, entryData) 367 if err != nil { 368 return -1, err 369 } 370 return int64(entrySACMData0Size), nil 371 } 372 373 // Write compiles the SACM v0 headers into a binary representation 374 func (entryData *EntrySACMData0) Write(b []byte) (int, error) { 375 n, err := entryData.WriteTo(bytesextra.NewReadWriteSeeker(b)) 376 return int(n), err 377 } 378 379 // WriteTo compiles the SACM v0 headers into a binary representation 380 func (entryData *EntrySACMData0) WriteTo(w io.Writer) (int64, error) { 381 err := binary.Write(w, binary.LittleEndian, entryData) 382 if err != nil { 383 return -1, err 384 } 385 return int64(entrySACMData0Size), nil 386 } 387 388 // GetRSAPubKey returns the RSA public key 389 func (entryData *EntrySACMData0) GetRSAPubKey() rsa.PublicKey { 390 pubKey := rsa.PublicKey{ 391 N: big.NewInt(0), 392 E: int(entryData.GetRSAPubExp()), 393 } 394 pubKey.N.SetBytes(entryData.RSAPubKey[:]) 395 return pubKey 396 } 397 398 // GetRSAPubExp returns the RSA exponent 399 func (entryData *EntrySACMData0) GetRSAPubExp() uint32 { 400 return binary.LittleEndian.Uint32(entryData.RSAPubExp[:]) 401 } 402 403 // GetRSASig returns the RSA signature. 404 func (entryData *EntrySACMData0) GetRSASig() []byte { return entryData.RSASig[:] } 405 406 // RSASigBinaryOffset returns the RSA signature offset 407 func (entryData *EntrySACMData0) RSASigBinaryOffset() uint64 { 408 return uint64(binary.Size(entryData.EntrySACMDataCommon)) + 409 uint64(binary.Size(entryData.RSAPubKey)) + 410 uint64(binary.Size(entryData.RSAPubExp)) 411 } 412 413 // GetScratch returns the Scratch field value 414 func (entryData *EntrySACMData0) GetScratch() []byte { return entryData.Scratch[:] } 415 416 // EntrySACMData3 is the structure for ACM of version 3.0 417 type EntrySACMData3 struct { 418 EntrySACMDataCommon 419 420 RSAPubKey [384]byte 421 RSASig [384]byte 422 Scratch [832]byte 423 } 424 425 var entrySACMData3Size = uint(binary.Size(EntrySACMData3{})) 426 427 // Read parses the ACM v3 headers 428 func (entryData *EntrySACMData3) Read(b []byte) (int, error) { 429 n, err := entryData.ReadFrom(bytesextra.NewReadWriteSeeker(b)) 430 return int(n), err 431 } 432 433 // ReadFrom parses the ACM v3 headers 434 func (entryData *EntrySACMData3) ReadFrom(r io.Reader) (int64, error) { 435 err := binary.Read(r, binary.LittleEndian, entryData) 436 if err != nil { 437 return -1, err 438 } 439 return int64(entrySACMData3Size), nil 440 } 441 442 // Write compiles the SACM v3 headers into a binary representation 443 func (entryData *EntrySACMData3) Write(b []byte) (int, error) { 444 n, err := entryData.WriteTo(bytesextra.NewReadWriteSeeker(b)) 445 return int(n), err 446 } 447 448 // WriteTo compiles the SACM v3 headers into a binary representation 449 func (entryData *EntrySACMData3) WriteTo(w io.Writer) (int64, error) { 450 err := binary.Write(w, binary.LittleEndian, entryData) 451 if err != nil { 452 return -1, err 453 } 454 return int64(entrySACMData3Size), nil 455 } 456 457 // GetRSAPubKey returns the RSA public key 458 func (entryData *EntrySACMData3) GetRSAPubKey() rsa.PublicKey { 459 pubKey := rsa.PublicKey{ 460 N: big.NewInt(0), 461 E: 0x10001, // see Table 9. "RSAPubExp" of https://www.intel.com/content/www/us/en/software-developers/txt-software-development-guide.html 462 } 463 pubKey.N.SetBytes(entryData.RSAPubKey[:]) 464 return pubKey 465 } 466 467 // GetRSASig returns the RSA signature. 468 func (entryData *EntrySACMData3) GetRSASig() []byte { return entryData.RSASig[:] } 469 470 // RSASigBinaryOffset returns the RSA signature offset 471 func (entryData *EntrySACMData3) RSASigBinaryOffset() uint64 { 472 return uint64(binary.Size(entryData.EntrySACMDataCommon)) + 473 uint64(binary.Size(entryData.RSAPubKey)) 474 } 475 476 // GetScratch returns the Scratch field value 477 func (entryData *EntrySACMData3) GetScratch() []byte { return entryData.Scratch[:] } 478 479 // EntrySACMData combines the structure for ACM and the user area. 480 type EntrySACMData struct { 481 EntrySACMDataInterface 482 483 UserArea []byte 484 } 485 486 // Read parses the ACM 487 func (entryData *EntrySACMData) Read(b []byte) (int, error) { 488 n, err := entryData.ReadFrom(bytesextra.NewReadWriteSeeker(b)) 489 return int(n), err 490 } 491 492 // ReadFrom parses the ACM 493 func (entryData *EntrySACMData) ReadFrom(r io.Reader) (int64, error) { 494 parsedEntryData, err := ParseSACMData(r) 495 if err != nil { 496 return -1, err 497 } 498 *entryData = *parsedEntryData 499 return int64(binary.Size(entryData.EntrySACMDataInterface) + len(entryData.UserArea)), nil 500 } 501 502 // Write compiles the SACM into a binary representation 503 func (entryData *EntrySACMData) Write(b []byte) (int, error) { 504 n, err := entryData.WriteTo(bytesextra.NewReadWriteSeeker(b)) 505 return int(n), err 506 } 507 508 // WriteTo compiles the SACM into a binary representation 509 func (entryData *EntrySACMData) WriteTo(w io.Writer) (int64, error) { 510 totalN, err := entryData.EntrySACMDataInterface.WriteTo(w) 511 if err != nil { 512 return -1, err 513 } 514 n, err := w.Write(entryData.UserArea) 515 if n >= 0 { 516 totalN += int64(n) 517 } 518 if err != nil { 519 return totalN, fmt.Errorf("unable to write UserArea: %w", err) 520 } 521 if n != len(entryData.UserArea) { 522 return totalN, fmt.Errorf("unable to complete writing UserArea: %d != %d: %w", n, len(entryData.UserArea), err) 523 } 524 return totalN, nil 525 } 526 527 // GetCommon returns the common part of the structures for different ACM versions. 528 func (entryData *EntrySACMData) GetCommon() *EntrySACMDataCommon { 529 if entryData == nil { 530 return nil 531 } 532 switch data := entryData.EntrySACMDataInterface.(type) { 533 case *EntrySACMDataCommon: 534 return data 535 case *EntrySACMData0: 536 return &data.EntrySACMDataCommon 537 case *EntrySACMData3: 538 return &data.EntrySACMDataCommon 539 } 540 return nil 541 } 542 543 // EntrySACMParseSizeFrom parses SACM structure size 544 func EntrySACMParseSizeFrom(r io.ReadSeeker, offset uint64) (uint32, error) { 545 sizeFieldLocalOffset := EntrySACMDataCommon{}.SizeBinaryOffset() 546 sizeFieldOffset := int64(offset) + int64(sizeFieldLocalOffset) 547 _, err := r.Seek(sizeFieldOffset, io.SeekStart) 548 if err != nil { 549 return 0, fmt.Errorf("unable to seek(%d, start): %w", sizeFieldOffset, err) 550 } 551 var result uint32 552 err = binary.Read(r, binary.LittleEndian, &result) 553 if err != nil { 554 return 0, fmt.Errorf("unable to read: %w", err) 555 } 556 return result << 2, nil 557 } 558 559 // EntrySACMParseSize parses SACM structure size 560 func EntrySACMParseSize(b []byte) (uint32, error) { 561 sizeFieldOffset := EntrySACMDataCommon{}.SizeBinaryOffset() 562 if int(sizeFieldOffset) >= len(b)-4 { 563 return 0, &check.ErrEndLessThanStart{StartIdx: int(sizeFieldOffset), EndIdx: len(b) - 4} 564 } 565 return binary.LittleEndian.Uint32(b[sizeFieldOffset:]) << 2, nil 566 } 567 568 // ParseData parses SACM entry and returns EntrySACMData. 569 func (entry *EntrySACM) ParseData() (*EntrySACMData, error) { 570 entryData := EntrySACMData{} 571 _, err := entryData.Read(entry.DataSegmentBytes) 572 if err != nil { 573 return nil, err 574 } 575 return &entryData, nil 576 } 577 578 // ParseSACMData parses SACM entry and returns EntrySACMData. 579 func ParseSACMData(r io.Reader) (*EntrySACMData, error) { 580 581 // Read common headers 582 583 common := EntrySACMDataCommon{} 584 if _, err := common.ReadFrom(r); err != nil { 585 return nil, fmt.Errorf("unable to parse startup AC module entry: %w", err) 586 } 587 result := &EntrySACMData{EntrySACMDataInterface: &common, UserArea: nil} 588 589 var requiredKeySize uint64 590 switch common.HeaderVersion { 591 case ACHeaderVersion0: 592 result.EntrySACMDataInterface = &EntrySACMData0{EntrySACMDataCommon: common} 593 requiredKeySize = uint64(len(EntrySACMData0{}.RSAPubKey)) 594 case ACHeaderVersion3: 595 result.EntrySACMDataInterface = &EntrySACMData3{EntrySACMDataCommon: common} 596 requiredKeySize = uint64(len(EntrySACMData3{}.RSAPubKey)) 597 default: 598 return result, &ErrUnknownACMHeaderVersion{ACHeaderVersion: common.HeaderVersion} 599 } 600 601 if common.KeySize.Size() != requiredKeySize { 602 return result, &ErrACMInvalidKeySize{ExpectedKeySize: requiredKeySize, RealKeySize: common.KeySize.Size()} 603 } 604 605 // Read version-specific headers 606 // 607 // Here we need to continue reading from the reader, 608 // but in the resulting struct we need to skip the first field (because it contains 609 // already read common headers). 610 611 // Creating a substruct without the first field (which is already read) 612 t := reflect.TypeOf(result.EntrySACMDataInterface).Elem() 613 var fieldsToBeFilled []reflect.StructField 614 for fieldNum := 1; fieldNum < t.NumField(); fieldNum++ { 615 fieldsToBeFilled = append(fieldsToBeFilled, t.Field(fieldNum)) 616 } 617 subStructToBeFilled := reflect.New(reflect.StructOf(fieldsToBeFilled)) 618 // Reading the substruct 619 if err := binary.Read(r, binary.LittleEndian, subStructToBeFilled.Interface()); err != nil { 620 return result, fmt.Errorf("cannot parse version-specific headers (version 0x%04X): %w", common.HeaderVersion, err) 621 } 622 // Copying values from the substruct to the headers struct 623 subStructToBeFilled = subStructToBeFilled.Elem() 624 v := reflect.ValueOf(result.EntrySACMDataInterface).Elem() 625 for fieldNum := 1; fieldNum < v.NumField(); fieldNum++ { 626 v.Field(fieldNum).Set(subStructToBeFilled.Field(fieldNum - 1)) 627 } 628 629 // Read UserArea 630 631 // `UserArea` has variable length and therefore was not included into 632 // `EntrySACMData0` and `EntrySACMData3`, but it is in the tail, 633 // so we just calculate the startIndex as the end of 634 // EntrySACMData0/EntrySACMData3. 635 userAreaStartIdx := uint64(binary.Size(result.EntrySACMDataInterface)) 636 userAreaEndIdx := result.EntrySACMDataInterface.GetSize().Size() 637 if userAreaEndIdx > userAreaStartIdx { 638 var err error 639 result.UserArea, err = readBytesFromReader(r, userAreaEndIdx-userAreaStartIdx) 640 if err != nil { 641 return result, fmt.Errorf("unable to read user area: %w", err) 642 } 643 } 644 645 return result, nil 646 } 647 648 type entrySACMJSON struct { 649 Headers *EntryHeaders 650 DataParsed *EntrySACMData `json:",omitempty"` 651 DataNotParsed []byte `json:"DataNotParsedBase64,omitempty"` 652 HeadersErrors []error 653 DataParseError error 654 } 655 656 // MarshalJSON implements json.Marshaler 657 func (entry *EntrySACM) MarshalJSON() ([]byte, error) { 658 result := entrySACMJSON{} 659 result.DataParsed, result.DataParseError = entry.ParseData() 660 result.Headers = &entry.Headers 661 result.HeadersErrors = make([]error, len(entry.HeadersErrors)) 662 copy(result.HeadersErrors, entry.HeadersErrors) 663 result.DataNotParsed = entry.DataSegmentBytes 664 return json.Marshal(&result) 665 } 666 667 // UnmarshalJSON implements json.Unmarshaller 668 func (entry *EntrySACM) UnmarshalJSON(b []byte) error { 669 result := entrySACMJSON{} 670 err := json.Unmarshal(b, &result) 671 if err != nil { 672 return err 673 } 674 entry.Headers = *result.Headers 675 entry.HeadersErrors = result.HeadersErrors 676 entry.DataSegmentBytes = result.DataNotParsed 677 return nil 678 }