1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package signjar
18
19 import (
20 "archive/zip"
21 "bytes"
22 "context"
23 "crypto"
24 "crypto/ecdsa"
25 "crypto/rsa"
26 "crypto/x509"
27 "encoding/asn1"
28 "errors"
29 "path"
30 "strings"
31 "time"
32
33 "github.com/sassoftware/relic/lib/binpatch"
34 "github.com/sassoftware/relic/lib/certloader"
35 "github.com/sassoftware/relic/lib/pkcs7"
36 "github.com/sassoftware/relic/lib/pkcs9"
37 "github.com/sassoftware/relic/lib/zipslicer"
38 )
39
40 func (jd *JarDigest) Sign(ctx context.Context, cert *certloader.Certificate, alias string, sectionsOnly, inlineSignature, apkV2 bool) (*binpatch.PatchSet, *pkcs9.TimestampedSignature, error) {
41
42 sf, err := DigestManifest(jd.Manifest, jd.Hash, sectionsOnly, apkV2)
43 if err != nil {
44 return nil, nil, err
45 }
46
47 sig := pkcs7.NewBuilder(cert.Signer(), cert.Chain(), jd.Hash)
48 if err := sig.SetContentData(sf); err != nil {
49 return nil, nil, err
50 }
51 psd, err := sig.Sign()
52 if err != nil {
53 return nil, nil, err
54 }
55 ts, err := pkcs9.TimestampAndMarshal(ctx, psd, cert.Timestamper, false)
56 if err != nil {
57 return nil, nil, err
58 }
59
60 psig := ts.Raw
61 if !inlineSignature {
62 if _, err := psd.Detach(); err != nil {
63 return nil, nil, err
64 }
65 psig, err = asn1.Marshal(*psd)
66 if err != nil {
67 return nil, nil, err
68 }
69 }
70 patch, err := jd.insertSignature(cert.Leaf, alias, sf, psig)
71 if err != nil {
72 return nil, nil, err
73 }
74 return patch, ts, nil
75 }
76
77 func (jd *JarDigest) insertSignature(cert *x509.Certificate, alias string, sf, sig []byte) (*binpatch.PatchSet, error) {
78 signame, pkcsname := sigNames(cert.PublicKey, alias)
79 deflate := jd.shouldDeflate()
80
81 outz := new(zipslicer.Directory)
82 var zipcon bytes.Buffer
83 mtime := time.Now()
84 if _, err := outz.NewFile(metaInf, jarMagic, nil, &zipcon, mtime, false, false); err != nil {
85 return nil, err
86 }
87 if _, err := outz.NewFile(manifestName, jarMagic, jd.Manifest, &zipcon, mtime, deflate, false); err != nil {
88 return nil, err
89 }
90 if _, err := outz.NewFile(metaInf+signame, nil, sf, &zipcon, mtime, deflate, false); err != nil {
91 return nil, err
92 }
93 if _, err := outz.NewFile(metaInf+pkcsname, nil, sig, &zipcon, mtime, deflate, false); err != nil {
94 return nil, err
95 }
96
97 patch := binpatch.New()
98 patch.Add(0, 0, zipcon.Bytes())
99 for _, f := range jd.inz.File {
100 if keepFile(f.Name) {
101
102 if _, err := outz.AddFile(f); err != nil {
103 return nil, err
104 }
105 } else {
106
107 size, err := f.GetTotalSize()
108 if err != nil {
109 return nil, err
110 }
111 if size > 0xffffffff {
112 return nil, errors.New("signature file too big")
113 }
114 patch.Add(int64(f.Offset), size, nil)
115 }
116 }
117 zipdir := new(bytes.Buffer)
118 if err := outz.WriteDirectory(zipdir, zipdir, false); err != nil {
119 return nil, err
120 }
121 patch.Add(jd.inz.DirLoc, jd.inz.Size-jd.inz.DirLoc, zipdir.Bytes())
122 return patch, nil
123 }
124
125
126 func sigNames(pubkey crypto.PublicKey, alias string) (signame, pkcsname string) {
127 signame = strings.ToUpper(alias) + ".SF"
128 pkcsname = strings.ToUpper(alias)
129 switch pubkey.(type) {
130 case *rsa.PublicKey:
131 pkcsname += ".RSA"
132 case *ecdsa.PublicKey:
133 pkcsname += ".EC"
134 default:
135 signame = "SIG-" + signame
136 pkcsname = "SIG-" + pkcsname + ".SIG"
137 }
138 return
139 }
140
141
142 func (jd *JarDigest) shouldDeflate() bool {
143 for _, f := range jd.inz.File {
144 if f.Name == manifestName {
145 return f.Method != zip.Store
146 }
147 }
148 return false
149 }
150
151 func keepFile(name string) bool {
152 if name == metaInf {
153
154 return false
155 }
156 if path.Dir(name)+"/" != metaInf {
157
158 return true
159 }
160 name = path.Base(name)
161 if strings.HasPrefix(name, "SIG-") {
162
163 return false
164 }
165 switch path.Ext(name) {
166 case ".MF":
167
168 return false
169 case ".SF":
170
171 return false
172 case ".RSA", ".DSA", ".EC", ".SIG":
173 return false
174 default:
175
176 return true
177 }
178 }
179
View as plain text