82
82
*/
83
83
@ Internal
84
84
public class TrustedCertificateStore implements ConscryptCertStore {
85
+ private static final String PREFIX_MANAGED = "managed:" ;
85
86
private static String PREFIX_SYSTEM = "system:" ;
86
87
private static final String PREFIX_USER = "user:" ;
87
88
89
+ public static final boolean isManaged (String alias ) {
90
+ return alias .startsWith (PREFIX_MANAGED );
91
+ }
88
92
public static final boolean isSystem (String alias ) {
89
93
return alias .startsWith (PREFIX_SYSTEM );
90
94
}
@@ -93,6 +97,7 @@ public static final boolean isUser(String alias) {
93
97
}
94
98
95
99
private static class PreloadHolder {
100
+ private static File defaultCaCertsManagedDir ;
96
101
private static File defaultCaCertsSystemDir ;
97
102
private static File defaultCaCertsAddedDir ;
98
103
private static File defaultCaCertsDeletedDir ;
@@ -101,6 +106,7 @@ private static class PreloadHolder {
101
106
String ANDROID_ROOT = System .getenv ("ANDROID_ROOT" );
102
107
String ANDROID_DATA = System .getenv ("ANDROID_DATA" );
103
108
File updatableDir = new File ("/apex/com.android.conscrypt/cacerts" );
109
+ defaultCaCertsManagedDir = new File (ANDROID_DATA + "/misc/cacerts_managed" );
104
110
if (shouldUseApex (updatableDir )) {
105
111
defaultCaCertsSystemDir = updatableDir ;
106
112
} else {
@@ -147,20 +153,23 @@ public static void setDefaultUserDirectory(File root) {
147
153
PreloadHolder .defaultCaCertsDeletedDir = new File (root , "cacerts-removed" );
148
154
}
149
155
156
+ private final File managedDir ;
150
157
private final File systemDir ;
151
158
private final File addedDir ;
152
159
private final File deletedDir ;
153
160
154
161
public TrustedCertificateStore () {
155
- this (PreloadHolder .defaultCaCertsSystemDir , PreloadHolder .defaultCaCertsAddedDir ,
156
- PreloadHolder .defaultCaCertsDeletedDir );
162
+ this (PreloadHolder .defaultCaCertsManagedDir , PreloadHolder .defaultCaCertsSystemDir ,
163
+ PreloadHolder .defaultCaCertsAddedDir , PreloadHolder . defaultCaCertsDeletedDir );
157
164
}
158
165
159
166
public TrustedCertificateStore (File baseDir ) {
160
- this (baseDir , PreloadHolder .defaultCaCertsAddedDir , PreloadHolder .defaultCaCertsDeletedDir );
167
+ this (PreloadHolder .defaultCaCertsManagedDir , baseDir , PreloadHolder .defaultCaCertsAddedDir ,
168
+ PreloadHolder .defaultCaCertsDeletedDir );
161
169
}
162
170
163
- public TrustedCertificateStore (File systemDir , File addedDir , File deletedDir ) {
171
+ public TrustedCertificateStore (File managedDir , File systemDir , File addedDir , File deletedDir ) {
172
+ this .managedDir = managedDir ;
164
173
this .systemDir = systemDir ;
165
174
this .addedDir = addedDir ;
166
175
this .deletedDir = deletedDir ;
@@ -173,7 +182,7 @@ public Certificate getCertificate(String alias) {
173
182
public Certificate getCertificate (String alias , boolean includeDeletedSystem ) {
174
183
175
184
File file = fileForAlias (alias );
176
- if (file == null || (isUser (alias ) && isTombstone (file ))) {
185
+ if (file == null || (isUser (alias ) && isTombstone (file )) || ( isManaged ( alias ) && isTombstone ( file )) ) {
177
186
return null ;
178
187
}
179
188
X509Certificate cert = readCertificate (file );
@@ -193,6 +202,8 @@ private File fileForAlias(String alias) {
193
202
File file ;
194
203
if (isSystem (alias )) {
195
204
file = new File (systemDir , alias .substring (PREFIX_SYSTEM .length ()));
205
+ } else if (isManaged (alias )) {
206
+ file = new File (managedDir , alias .substring (PREFIX_MANAGED .length ()));
196
207
} else if (isUser (alias )) {
197
208
file = new File (addedDir , alias .substring (PREFIX_USER .length ()));
198
209
} else {
@@ -268,6 +279,7 @@ public Date getCreationDate(String alias) {
268
279
269
280
public Set <String > aliases () {
270
281
Set <String > result = new HashSet <String >();
282
+ addAliases (result , PREFIX_MANAGED , managedDir );
271
283
addAliases (result , PREFIX_USER , addedDir );
272
284
addAliases (result , PREFIX_SYSTEM , systemDir );
273
285
return result ;
@@ -292,6 +304,21 @@ private void addAliases(Set<String> result, String prefix, File dir) {
292
304
}
293
305
}
294
306
307
+ public Set <String > allManagedAliases () {
308
+ Set <String > result = new HashSet <String >();
309
+ String [] files = managedDir .list ();
310
+ if (files == null ) {
311
+ return result ;
312
+ }
313
+ for (String filename : files ) {
314
+ String alias = PREFIX_MANAGED + filename ;
315
+ if (containsAlias (alias , true )) {
316
+ result .add (alias );
317
+ }
318
+ }
319
+ return result ;
320
+ }
321
+
295
322
public Set <String > allSystemAliases () {
296
323
Set <String > result = new HashSet <String >();
297
324
String [] files = systemDir .list ();
@@ -324,6 +351,10 @@ public String getCertificateAlias(Certificate c, boolean includeDeletedSystem) {
324
351
return null ;
325
352
}
326
353
X509Certificate x = (X509Certificate ) c ;
354
+ File managed = getCertificateFile (managedDir , x );
355
+ if (managed .exists ()) {
356
+ return PREFIX_MANAGED + managed .getName ();
357
+ }
327
358
File user = getCertificateFile (addedDir , x );
328
359
if (user .exists ()) {
329
360
return PREFIX_USER + user .getName ();
@@ -338,6 +369,14 @@ public String getCertificateAlias(Certificate c, boolean includeDeletedSystem) {
338
369
return null ;
339
370
}
340
371
372
+ /**
373
+ * Returns true to indicate that the certificate was added by the
374
+ * device owner, false otherwise.
375
+ */
376
+ public boolean isManagedCertificate (X509Certificate cert ) {
377
+ return getCertificateFile (managedDir , cert ).exists ();
378
+ }
379
+
341
380
/**
342
381
* Returns true to indicate that the certificate was added by the
343
382
* user, false otherwise.
@@ -383,6 +422,13 @@ public boolean match(X509Certificate ca) {
383
422
return ca .getPublicKey ().equals (c .getPublicKey ());
384
423
}
385
424
};
425
+ X509Certificate managed = findCert (managedDir ,
426
+ c .getSubjectX500Principal (),
427
+ selector ,
428
+ X509Certificate .class );
429
+ if (managed != null ) {
430
+ return managed ;
431
+ }
386
432
X509Certificate user = findCert (addedDir ,
387
433
c .getSubjectX500Principal (),
388
434
selector ,
@@ -419,6 +465,10 @@ public boolean match(X509Certificate ca) {
419
465
}
420
466
};
421
467
X500Principal issuer = c .getIssuerX500Principal ();
468
+ X509Certificate managed = findCert (managedDir , issuer , selector , X509Certificate .class );
469
+ if (managed != null ) {
470
+ return managed ;
471
+ }
422
472
X509Certificate user = findCert (addedDir , issuer , selector , X509Certificate .class );
423
473
if (user != null ) {
424
474
return user ;
@@ -445,6 +495,10 @@ public boolean match(X509Certificate ca) {
445
495
}
446
496
};
447
497
X500Principal issuer = c .getIssuerX500Principal ();
498
+ Set <X509Certificate > managedCerts = findCertSet (managedDir , issuer , selector );
499
+ if (managedCerts != null ) {
500
+ issuers = managedCerts ;
501
+ }
448
502
Set <X509Certificate > userAddedCerts = findCertSet (addedDir , issuer , selector );
449
503
if (userAddedCerts != null ) {
450
504
issuers = userAddedCerts ;
@@ -603,13 +657,21 @@ private File file(File dir, String hash, int index) {
603
657
return new File (dir , hash + '.' + index );
604
658
}
605
659
660
+ /**
661
+ * @deprecated Use {@link #installCertificate(boolean[], java.security.cert.X509Certificate)} instead.
662
+ */
663
+ @ Deprecated
664
+ public void installCertificate (X509Certificate cert ) throws IOException , CertificateException {
665
+ installCertificate (false , cert );
666
+ }
667
+
606
668
/**
607
669
* This non-{@code KeyStoreSpi} public interface is used by the
608
670
* {@code KeyChainService} to install new CA certificates. It
609
671
* silently ignores the certificate if it already exists in the
610
672
* store.
611
673
*/
612
- public void installCertificate (X509Certificate cert ) throws IOException , CertificateException {
674
+ public void installCertificate (boolean isManaged , X509Certificate cert ) throws IOException , CertificateException {
613
675
if (cert == null ) {
614
676
throw new NullPointerException ("cert == null" );
615
677
}
@@ -628,6 +690,13 @@ public void installCertificate(X509Certificate cert) throws IOException, Certifi
628
690
// return taking no further action.
629
691
return ;
630
692
}
693
+ File managed = getCertificateFile (managedDir , cert );
694
+ if (isManaged ) {
695
+ if (!managed .exists ()) {
696
+ writeCertificate (managed , cert );
697
+ }
698
+ return ;
699
+ }
631
700
File user = getCertificateFile (addedDir , cert );
632
701
if (user .exists ()) {
633
702
// we have an already installed user cert, bail.
@@ -667,7 +736,7 @@ public void deleteCertificateEntry(String alias) throws IOException, Certificate
667
736
writeCertificate (deleted , cert );
668
737
return ;
669
738
}
670
- if (isUser (alias )) {
739
+ if (isUser (alias ) || isManaged ( alias ) ) {
671
740
// truncate the file to make a tombstone by opening and closing.
672
741
// we need ensure that we don't leave a gap before a valid cert.
673
742
new FileOutputStream (file ).close ();
@@ -678,22 +747,32 @@ public void deleteCertificateEntry(String alias) throws IOException, Certificate
678
747
}
679
748
680
749
private void removeUnnecessaryTombstones (String alias ) throws IOException {
681
- if (!isUser (alias )) {
750
+ if (!isUser (alias ) && ! isManaged ( alias ) ) {
682
751
throw new AssertionError (alias );
683
752
}
684
753
int dotIndex = alias .lastIndexOf ('.' );
685
754
if (dotIndex == -1 ) {
686
755
throw new AssertionError (alias );
687
756
}
688
757
689
- String hash = alias .substring (PREFIX_USER .length (), dotIndex );
758
+ File dir = null ;
759
+ String hash = null ;
760
+ if (isUser (alias )) {
761
+ dir = addedDir ;
762
+ hash = alias .substring (PREFIX_USER .length (), dotIndex );
763
+ } else if (isManaged (alias )) {
764
+ dir = managedDir ;
765
+ hash = alias .substring (PREFIX_MANAGED .length (), dotIndex );
766
+ } else {
767
+ throw new AssertionError (alias );
768
+ }
690
769
int lastTombstoneIndex = Integer .parseInt (alias .substring (dotIndex + 1 ));
691
770
692
- if (file (addedDir , hash , lastTombstoneIndex + 1 ).exists ()) {
771
+ if (file (dir , hash , lastTombstoneIndex + 1 ).exists ()) {
693
772
return ;
694
773
}
695
774
while (lastTombstoneIndex >= 0 ) {
696
- File file = file (addedDir , hash , lastTombstoneIndex );
775
+ File file = file (dir , hash , lastTombstoneIndex );
697
776
if (!isTombstone (file )) {
698
777
break ;
699
778
}
0 commit comments