1 package org.apache.maven.shared.jarsigner;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.shared.utils.io.FileUtils;
23 import org.apache.maven.shared.utils.io.IOUtil;
24
25 import java.io.BufferedInputStream;
26 import java.io.BufferedOutputStream;
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileOutputStream;
30 import java.io.IOException;
31 import java.util.Map;
32 import java.util.jar.Attributes;
33 import java.util.jar.Manifest;
34 import java.util.zip.ZipEntry;
35 import java.util.zip.ZipInputStream;
36 import java.util.zip.ZipOutputStream;
37
38
39
40
41
42
43
44 public class JarSignerUtil
45 {
46
47 private JarSignerUtil()
48 {
49
50 }
51
52
53
54
55
56
57
58
59 public static boolean isZipFile( final File file )
60 {
61 boolean result = false;
62
63 try ( ZipInputStream zis = new ZipInputStream( new FileInputStream( file ) ) )
64 {
65 result = zis.getNextEntry() != null;
66 }
67 catch ( Exception e )
68 {
69
70 }
71
72 return result;
73 }
74
75
76
77
78
79
80
81
82 public static void unsignArchive( File jarFile )
83 throws IOException
84 {
85
86 File unsignedFile = new File( jarFile.getAbsolutePath() + ".unsigned" );
87
88 try ( ZipInputStream zis = new ZipInputStream( new BufferedInputStream( new FileInputStream( jarFile ) ) );
89 ZipOutputStream zos =
90 new ZipOutputStream( new BufferedOutputStream( new FileOutputStream( unsignedFile ) ) ) )
91 {
92 for ( ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry() )
93 {
94 if ( isSignatureFile( ze.getName() ) )
95 {
96 continue;
97 }
98
99 zos.putNextEntry( new ZipEntry( ze.getName() ) );
100
101 if ( isManifestFile( ze.getName() ) )
102 {
103
104
105
106 Manifest oldManifest = new Manifest( zis );
107 Manifest newManifest = buildUnsignedManifest( oldManifest );
108 newManifest.write( zos );
109
110 continue;
111 }
112
113 IOUtil.copy( zis, zos );
114 }
115
116 }
117
118 FileUtils.rename( unsignedFile, jarFile );
119
120 }
121
122
123
124
125
126
127
128
129
130
131
132 protected static Manifest buildUnsignedManifest( Manifest manifest )
133 {
134 Manifest result = new Manifest( manifest );
135 result.getEntries().clear();
136
137 for ( Map.Entry<String, Attributes> manifestEntry : manifest.getEntries().entrySet() )
138 {
139 Attributes oldAttributes = manifestEntry.getValue();
140 Attributes newAttributes = new Attributes();
141
142 for ( Map.Entry<Object, Object> attributesEntry : oldAttributes.entrySet() )
143 {
144 String attributeKey = String.valueOf( attributesEntry.getKey() );
145 if ( !attributeKey.endsWith( "-Digest" ) )
146 {
147
148 newAttributes.put( attributesEntry.getKey(), attributesEntry.getValue() );
149 }
150 }
151
152 if ( !newAttributes.isEmpty() )
153 {
154
155 result.getEntries().put( manifestEntry.getKey(), newAttributes );
156 }
157 }
158
159 return result;
160 }
161
162
163
164
165
166
167
168
169
170 public static boolean isArchiveSigned( final File jarFile )
171 throws IOException
172 {
173 if ( jarFile == null )
174 {
175 throw new NullPointerException( "jarFile" );
176 }
177
178 try ( ZipInputStream in = new ZipInputStream( new BufferedInputStream( new FileInputStream( jarFile ) ) ) )
179 {
180 boolean signed = false;
181
182 for ( ZipEntry ze = in.getNextEntry(); ze != null; ze = in.getNextEntry() )
183 {
184 if ( isSignatureFile( ze.getName() ) )
185 {
186 signed = true;
187 break;
188 }
189 }
190
191 return signed;
192 }
193 }
194
195
196
197
198
199
200
201
202
203 protected static boolean isSignatureFile( String entryName )
204 {
205 if ( entryName.regionMatches( true, 0, "META-INF", 0, 8 ) )
206 {
207 entryName = entryName.replace( '\\', '/' );
208
209 if ( entryName.indexOf( '/' ) == 8 && entryName.lastIndexOf( '/' ) == 8 )
210 {
211 return endsWithIgnoreCase( entryName, ".SF" ) || endsWithIgnoreCase( entryName, ".DSA" )
212 || endsWithIgnoreCase( entryName, ".RSA" ) || endsWithIgnoreCase( entryName, ".EC" );
213 }
214 }
215 return false;
216 }
217
218 protected static boolean isManifestFile( String entryName )
219 {
220 if ( entryName.regionMatches( true, 0, "META-INF", 0, 8 ) )
221 {
222 entryName = entryName.replace( '\\', '/' );
223
224 if ( entryName.indexOf( '/' ) == 8 && entryName.lastIndexOf( '/' ) == 8 )
225 {
226 return endsWithIgnoreCase( entryName, "/MANIFEST.MF" );
227 }
228 }
229 return false;
230 }
231
232 private static boolean endsWithIgnoreCase( String str, String searchStr )
233 {
234 return str.regionMatches( true, str.length() - searchStr.length(), searchStr, 0, searchStr.length() );
235 }
236 }