1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package apk
18
19 import (
20 "bytes"
21 "crypto"
22 "crypto/rand"
23 "encoding/binary"
24 "io"
25
26 "github.com/pkg/errors"
27 "github.com/sassoftware/relic/lib/binpatch"
28 "github.com/sassoftware/relic/lib/certloader"
29 "github.com/sassoftware/relic/lib/x509tools"
30 "github.com/sassoftware/relic/lib/zipslicer"
31 )
32
33 type Digest struct {
34 inz *zipslicer.Directory
35 hash crypto.Hash
36 value []byte
37 sigLoc int64
38 }
39
40 func digestApkStream(r io.Reader, hash crypto.Hash) (*Digest, error) {
41 inz, err := zipslicer.ReadZipTar(r)
42 if err != nil {
43 return nil, err
44 }
45 hasher := newMerkleHasher([]crypto.Hash{hash})
46 for _, f := range inz.File {
47 _, err := f.Dump(hasher)
48 if err != nil {
49 return nil, err
50 }
51 }
52 sigLoc, err := inz.NextFileOffset()
53 if err != nil {
54 return nil, err
55 }
56 origDirLoc := inz.DirLoc
57 inz.DirLoc = sigLoc
58 digests, err := hasher.Finish(inz, true)
59 if err != nil {
60 return nil, err
61 }
62 inz.DirLoc = origDirLoc
63 return &Digest{
64 inz: inz,
65 hash: hash,
66 value: digests[0],
67 sigLoc: sigLoc,
68 }, nil
69 }
70
71 func (d *Digest) Sign(cert *certloader.Certificate) (*binpatch.PatchSet, error) {
72
73 alg := x509tools.GetPublicKeyAlgorithm(cert.Leaf.PublicKey)
74 var st sigType
75 for _, s := range sigTypes {
76 if s.hash == d.hash && s.alg == alg && !s.pss {
77 st = s
78 break
79 }
80
81 }
82 if st.id == 0 {
83 return nil, errors.New("unsupported public key algorithm")
84 }
85
86 sd := apkSignedData{
87 Digests: []apkDigest{apkDigest{ID: st.id, Value: d.value}},
88 }
89 for _, cert := range cert.Chain() {
90 sd.Certificates = append(sd.Certificates, cert.Raw)
91 }
92 signedData, err := marshal(sd)
93 if err != nil {
94 return nil, err
95 }
96
97 digest := st.hash.New()
98 digest.Write(signedData.Bytes())
99 sigv, err := cert.Signer().Sign(rand.Reader, digest.Sum(nil), st.hash)
100 if err != nil {
101 return nil, err
102 }
103
104 signerList := []apkSigner{apkSigner{
105 SignedData: signedData,
106 Signatures: []apkSignature{apkSignature{ID: st.id, Value: sigv}},
107 PublicKey: cert.Leaf.RawSubjectPublicKeyInfo,
108 }}
109 sblob, err := marshal(signerList)
110 if err != nil {
111 return nil, err
112 }
113 block := makeSigBlock(sblob)
114
115 patchset := binpatch.New()
116 origDirLoc := d.inz.DirLoc
117 patchset.Add(d.sigLoc, origDirLoc-d.sigLoc, block)
118 d.inz.DirLoc = d.sigLoc + int64(len(block))
119 var dirEnts, endOfDir bytes.Buffer
120 if err := d.inz.WriteDirectory(&dirEnts, &endOfDir, false); err != nil {
121 return nil, err
122 }
123 patchset.Add(origDirLoc+int64(dirEnts.Len()), int64(endOfDir.Len()), endOfDir.Bytes())
124 return patchset, nil
125 }
126
127 func makeSigBlock(sblob []byte) []byte {
128 block := make([]byte, 8+12+len(sblob)+24)
129
130 binary.LittleEndian.PutUint64(block, uint64(8+4+len(sblob)+8+16))
131
132 binary.LittleEndian.PutUint64(block[8:], uint64(4+len(sblob)))
133
134 binary.LittleEndian.PutUint32(block[8+8:], sigApkV2)
135
136 copy(block[8+8+4:], sblob)
137
138 suffix := block[8+8+4+len(sblob):]
139 copy(suffix, block[:8])
140 copy(suffix[8:], sigMagic)
141 return block
142 }
143
View as plain text